1 /* $NetBSD: clpssoc.c,v 1.1 2013/04/28 11:57:13 kiyohara Exp $ */ 2 /* 3 * Copyright (c) 2013 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: clpssoc.c,v 1.1 2013/04/28 11:57:13 kiyohara Exp $"); 30 31 #include "opt_com.h" 32 33 #define _INTR_PRIVATE 34 35 #include <sys/param.h> 36 #include <sys/bus.h> 37 #include <sys/device.h> 38 #include <sys/errno.h> 39 #include <sys/kernel.h> 40 #include <sys/systm.h> 41 #include <sys/timetc.h> 42 #include <sys/types.h> 43 44 #include <arm/mainbus/mainbus.h> 45 #include <arm/pic/picvar.h> 46 47 #include <machine/epoc32.h> 48 #include <machine/limits.h> 49 50 #include <arm/clps711x/clps711xreg.h> 51 #include <arm/clps711x/clpssocvar.h> 52 53 #include "locators.h" 54 55 56 static int clpssoc_match(device_t, cfdata_t, void *); 57 static void clpssoc_attach(device_t parent, device_t self, void *aux); 58 59 static int clpssoc_print(void *, const char *); 60 static int clpssoc_submatch(device_t, cfdata_t, const int *, void *); 61 62 static int clpssoc_find_pending_irqs(void); 63 64 static void clpssoc_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t); 65 static void clpssoc_pic_block_irqs(struct pic_softc *, size_t, uint32_t); 66 static void clpssoc_pic_establish_irq(struct pic_softc *, struct intrsource *); 67 68 #define INTSR (*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_INTSR))) 69 #define INTMR (*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_INTMR))) 70 #define SYSCON (*((volatile uint32_t *)(ARM7XX_INTRREG_VBASE + PS711X_SYSCON))) 71 #define TC1D (*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC1D))) 72 #define TC2D (*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC2D))) 73 static void clpssoc_initclocks(void); 74 static int clpssoc_clockintr(void *); 75 static void clpssoc_tc_init(void); 76 static u_int clpssoc_get_timecount(struct timecounter *); 77 78 static void clpssoc_delay(unsigned int); 79 80 CFATTACH_DECL_NEW(clpssoc, 0, clpssoc_match, clpssoc_attach, NULL, NULL); 81 82 static const struct { 83 const char *name; 84 int irq[3]; 85 } clpssoc_periphs[] = { 86 { "clpsaudio", {CLPSSOCCF_IRQ_DEFAULT} }, 87 { "clpscom", {12, 13, 14} }, 88 { "clpskbd", {CLPSSOCCF_IRQ_DEFAULT} }, 89 { "clpslcd", {CLPSSOCCF_IRQ_DEFAULT} }, 90 { "clpspm", {CLPSSOCCF_IRQ_DEFAULT} }, 91 { "clpsrtc", {10, CLPSSOCCF_IRQ_DEFAULT} }, 92 }; 93 94 extern struct bus_space clps711x_bs_tag; 95 96 static struct pic_ops clpssoc_picops = { 97 .pic_unblock_irqs = clpssoc_pic_unblock_irqs, 98 .pic_block_irqs = clpssoc_pic_block_irqs, 99 .pic_establish_irq = clpssoc_pic_establish_irq, 100 }; 101 static struct pic_softc clpssoc_pic = { 102 .pic_ops = &clpssoc_picops, 103 .pic_maxsources = 16, 104 .pic_name = "clpssoc", 105 }; 106 107 /* ARGSUSED */ 108 static int 109 clpssoc_match(device_t parent, cfdata_t match, void *aux) 110 { 111 112 return 1; 113 } 114 115 /* ARGSUSED */ 116 static void 117 clpssoc_attach(device_t parent, device_t self, void *aux) 118 { 119 struct mainbus_attach_args *maa = aux; 120 struct clpssoc_attach_args aa; 121 bus_space_handle_t ioh; 122 uint32_t sysflg; 123 int i, j; 124 125 if (bus_space_map(&clps711x_bs_tag, maa->mb_iobase, ARM7XX_INTRREG_SIZE, 126 0, &ioh) != 0) { 127 aprint_error_dev(self, "can't map registers\n"); 128 return; 129 } 130 sysflg = bus_space_read_4(&clps711x_bs_tag, ioh, PS711X_SYSFLG); 131 aprint_normal(": CL PS-711x rev %d\n", SYSFLG_VERID(sysflg)); 132 aprint_naive("\n"); 133 134 INTMR = 0; 135 136 pic_add(&clpssoc_pic, 0); 137 soc_find_pending_irqs = clpssoc_find_pending_irqs; 138 soc_initclocks = clpssoc_initclocks; 139 soc_delay = clpssoc_delay; 140 141 for (i = 0; i < __arraycount(clpssoc_periphs); i++) { 142 aa.aa_name = clpssoc_periphs[i].name; 143 aa.aa_iot = &clps711x_bs_tag; 144 aa.aa_ioh = &ioh; 145 for (j = 0; j < __arraycount(clpssoc_periphs[i].irq); j++) 146 aa.aa_irq[j] = clpssoc_periphs[i].irq[j]; 147 148 config_found_sm_loc(self, "clpssoc", NULL, &aa, 149 clpssoc_print, clpssoc_submatch); 150 } 151 } 152 153 static int 154 clpssoc_print(void *aux, const char *pnp) 155 { 156 struct clpssoc_attach_args *aa = aux; 157 int i; 158 159 if (pnp) 160 aprint_normal("%s at %s", aa->aa_name, pnp); 161 else 162 if (aa->aa_irq[0] != CLPSSOCCF_IRQ_DEFAULT) { 163 aprint_normal(" irq %d", aa->aa_irq[0]); 164 for (i = 1; i < __arraycount(aa->aa_irq); i++) { 165 if (aa->aa_irq[i] == CLPSSOCCF_IRQ_DEFAULT) 166 break; 167 aprint_normal(",%d", aa->aa_irq[i]); 168 } 169 } 170 171 return UNCONF; 172 } 173 174 /* ARGSUSED */ 175 static int 176 clpssoc_submatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 177 { 178 struct clpssoc_attach_args *aa = aux; 179 180 if (strcmp(aa->aa_name, "clpskbd") == 0 && 181 strcmp(cf->cf_name + strlen(cf->cf_name) - 3, "kbd") == 0) 182 return config_match(parent, cf, aux); 183 184 if (strcmp(cf->cf_name, aa->aa_name) != 0) 185 return 0; 186 return config_match(parent, cf, aux); 187 } 188 189 190 static int 191 clpssoc_find_pending_irqs(void) 192 { 193 uint16_t pending; 194 195 pending = INTSR; 196 pending &= INTMR; 197 if (pending == 0) 198 return 0; 199 200 return pic_mark_pending_sources(&clpssoc_pic, 0, pending); 201 } 202 203 /* ARGSUSED */ 204 static void 205 clpssoc_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase, 206 uint32_t irq_mask) 207 { 208 209 INTMR |= irq_mask; 210 } 211 212 /* ARGSUSED */ 213 static void 214 clpssoc_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask) 215 { 216 217 INTMR &= ~irq_mask; 218 } 219 220 static void 221 clpssoc_pic_establish_irq(struct pic_softc *pic, struct intrsource *is) 222 { 223 /* Nothing */ 224 } 225 226 static void 227 clpssoc_initclocks(void) 228 { 229 230 /* set prescale mode to TC1 and free-running mode TC2 */ 231 SYSCON |= (SYSCON_TC1M | SYSCON_TC1S | SYSCON_TC2S); 232 TC1D = 512 * 1000 / hz - 1; /* 512kHz / hz - 1 */ 233 intr_establish(IRQ_TC1DI, IPL_CLOCK, 0, clpssoc_clockintr, NULL); 234 235 clpssoc_tc_init(); 236 } 237 238 static int 239 clpssoc_clockintr(void *arg) 240 { 241 242 *(volatile uint32_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC1EOI) = 1; 243 244 hardclock(arg); 245 246 return 1; 247 } 248 249 static void 250 clpssoc_tc_init(void) 251 { 252 static struct timecounter clpssoc_tc = { 253 .tc_get_timecount = clpssoc_get_timecount, 254 .tc_counter_mask = UINT16_MAX, 255 .tc_frequency = 512000, 256 .tc_name = "clpssoc", 257 .tc_quality = 100, 258 }; 259 260 tc_init(&clpssoc_tc); 261 } 262 263 static u_int 264 clpssoc_get_timecount(struct timecounter *tc) 265 { 266 267 return TC2D ^ UINT16_MAX; /* It is decremental counter */ 268 } 269 270 static void 271 clpssoc_delay(unsigned int us) 272 { 273 int prev, now, remaining; 274 275 prev = TC2D & UINT16_MAX; 276 remaining = us * 512 / 1000 + 1; 277 278 while (remaining > 0) { 279 now = TC2D & UINT16_MAX; 280 if (now >= prev) 281 remaining -= (now - prev); 282 else 283 remaining -= (UINT16_MAX - now + prev + 1); 284 prev = now; 285 } 286 } 287