1 /* $NetBSD: gemini_lpc.c,v 1.3 2008/11/15 05:48:34 cliff Exp $ */ 2 3 #include "opt_gemini.h" 4 #include "locators.h" 5 6 #include <sys/cdefs.h> 7 __KERNEL_RCSID(0, "$NetBSD: gemini_lpc.c,v 1.3 2008/11/15 05:48:34 cliff Exp $"); 8 9 #include <sys/param.h> 10 #include <sys/systm.h> 11 #include <sys/device.h> 12 #include <arch/arm/gemini/gemini_lpcvar.h> 13 #include <arch/arm/gemini/gemini_lpchcvar.h> 14 #include <arch/arm/gemini/gemini_reg.h> 15 16 17 /* XXX these should be in lpcreg.h or it8721reg.h */ 18 #define IT8712_CFGCTL 0x02 19 # define CFGCTL_WAITKEY __BIT(1) 20 #define IT8712_LDN 0x07 21 #define IT8712_CHIPID1 0x20 22 #define IT8712_CHIPID2 0x21 23 #define IT8712_CSCV 0x22 24 # define CSCV_VERSION __BITS(3,0); 25 #define IT8712_CLKSEL 0x23 26 #define IT8712_SWSUSPEND 0x24 27 #define IT8712_ADDR 0x2e 28 #define IT8712_DATA 0x2f 29 30 static int gemini_lpc_match(struct device *, struct cfdata *, void *); 31 static void gemini_lpc_attach(struct device *, struct device *, void *); 32 static int gemini_lpc_search(device_t, cfdata_t, const int *, void *); 33 static int gemini_lpc_busprint(void *, const char *); 34 35 static uint8_t it8712_pnp_read(lpctag_t, int, uint); 36 static void it8712_pnp_write(lpctag_t, int, uint, uint8_t); 37 static void it8712_pnp_enter(lpctag_t); 38 static void it8712_pnp_exit(lpctag_t); 39 static void *it8712_intr_establish(lpctag_t, uint, int, int, int (*)(void *), void *); 40 static void it8712_intr_disestablish(lpctag_t, void *); 41 42 CFATTACH_DECL_NEW(lpc, sizeof(struct gemini_lpc_softc), 43 gemini_lpc_match, gemini_lpc_attach, NULL, NULL); 44 45 gemini_lpc_bus_ops_t gemini_lpc_bus_ops = { 46 it8712_pnp_read, 47 it8712_pnp_write, 48 it8712_pnp_enter, 49 it8712_pnp_exit, 50 it8712_intr_establish, 51 it8712_intr_disestablish, 52 }; 53 54 55 static int 56 gemini_lpc_match(struct device *parent, struct cfdata *cf, void *aux) 57 { 58 struct gemini_lpc_attach_args *lpc = aux; 59 60 if (lpc->lpc_addr == LPCCF_ADDR_DEFAULT) 61 panic("lpc must have addr specified in config."); 62 63 return 1; 64 } 65 66 static void 67 gemini_lpc_attach(struct device *parent, struct device *self, void *aux) 68 { 69 gemini_lpc_softc_t *sc = device_private(self); 70 struct gemini_lpchc_attach_args *lpchc = aux; 71 bus_space_tag_t iot; 72 bus_space_handle_t ioh; 73 uint8_t id1, id2, vers, clk, susp; 74 75 sc->sc_addr = lpchc->lpchc_addr; 76 #if 0 77 sc->sc_size = lpchc->lpchc_size; 78 #else 79 /* 80 * we just map the configuration registers 81 * child devices can map their own I/O 82 */ 83 sc->sc_size = 4096; 84 #endif 85 86 iot = lpchc->lpchc_iot; 87 if (bus_space_map(iot, sc->sc_addr, sc->sc_size, 0, &ioh)) 88 panic("%s: Cannot map registers", device_xname(self)); 89 sc->sc_iot = iot; 90 sc->sc_ioh = ioh; 91 92 it8712_pnp_enter(sc); 93 id1 = it8712_pnp_read(sc, GEMINI_LPC_LDN_ALL, IT8712_CHIPID1); 94 id2 = it8712_pnp_read(sc, GEMINI_LPC_LDN_ALL, IT8712_CHIPID2); 95 vers = it8712_pnp_read(sc, GEMINI_LPC_LDN_ALL, IT8712_CSCV); 96 vers &= CSCV_VERSION; 97 clk = it8712_pnp_read(sc, GEMINI_LPC_LDN_ALL, IT8712_CLKSEL); 98 susp = it8712_pnp_read(sc, GEMINI_LPC_LDN_ALL, IT8712_SWSUSPEND); 99 it8712_pnp_exit(sc); 100 101 aprint_normal("\n%s: chip ID %x%x, version %d", 102 device_xname(self), id1, id2, vers); 103 aprint_normal("\n%s: clksel %#x, susp %#x ", 104 device_xname(self), clk, susp); 105 106 sc->sc_lpchctag = lpchc->lpchc_tag; 107 sc->sc_bus_ops = &gemini_lpc_bus_ops; 108 109 aprint_normal("\n"); 110 aprint_naive("\n"); 111 112 /* 113 * attach the rest of our devices 114 */ 115 config_search_ia(gemini_lpc_search, self, "lpc", NULL); 116 } 117 118 static int 119 gemini_lpc_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 120 { 121 gemini_lpc_softc_t *sc = device_private(parent); 122 gemini_lpc_attach_args_t lpc; 123 124 lpc.lpc_ldn = cf->cf_loc[LPCCF_LDN]; 125 lpc.lpc_addr = cf->cf_loc[LPCCF_ADDR]; 126 lpc.lpc_size = cf->cf_loc[LPCCF_SIZE]; 127 lpc.lpc_intr = cf->cf_loc[LPCCF_INTR]; 128 lpc.lpc_iot = sc->sc_iot; 129 lpc.lpc_tag = sc; 130 lpc.lpc_base = sc->sc_addr; 131 132 if (config_match(parent, cf, &lpc)) { 133 config_attach(parent, cf, &lpc, gemini_lpc_busprint); 134 return 0; /* love it */ 135 } 136 137 return UNCONF; /* hate it */ 138 } 139 140 static int 141 gemini_lpc_busprint(void *aux, const char *name) 142 { 143 struct gemini_lpc_attach_args *lpc = aux; 144 145 if (lpc->lpc_ldn != LPCCF_LDN_DEFAULT) 146 aprint_normal(" ldn %d", lpc->lpc_ldn); 147 if (lpc->lpc_addr != LPCCF_ADDR_DEFAULT) 148 aprint_normal(" addr %#lx", lpc->lpc_addr); 149 if (lpc->lpc_size != LPCCF_SIZE_DEFAULT) 150 aprint_normal(" size %#lx", lpc->lpc_size); 151 if (lpc->lpc_intr != LPCCF_INTR_DEFAULT) 152 aprint_normal(" intr %d", lpc->lpc_intr); 153 154 return UNCONF; 155 } 156 157 /* 158 * LPC bus ops 159 */ 160 161 static uint8_t 162 it8712_pnp_read(lpctag_t tag, int ldn, uint index) 163 { 164 gemini_lpc_softc_t *sc = tag; 165 bus_space_tag_t iot = sc->sc_iot; 166 bus_space_handle_t ioh = sc->sc_ioh; 167 168 if (ldn != GEMINI_LPC_LDN_ALL) { 169 bus_space_write_1(iot, ioh, IT8712_ADDR, IT8712_LDN); 170 bus_space_write_1(iot, ioh, IT8712_DATA, ldn); 171 } 172 bus_space_write_1(iot, ioh, IT8712_ADDR, index); 173 return bus_space_read_1(iot, ioh, IT8712_DATA); 174 } 175 176 static void 177 it8712_pnp_write(lpctag_t tag, int ldn, uint index, uint8_t val) 178 { 179 gemini_lpc_softc_t *sc = tag; 180 bus_space_tag_t iot = sc->sc_iot; 181 bus_space_handle_t ioh = sc->sc_ioh; 182 183 if (ldn != GEMINI_LPC_LDN_ALL) { 184 bus_space_write_1(iot, ioh, IT8712_ADDR, IT8712_LDN); 185 bus_space_write_1(iot, ioh, IT8712_DATA, ldn); 186 } 187 bus_space_write_1(iot, ioh, IT8712_ADDR, index); 188 bus_space_write_1(iot, ioh, IT8712_DATA, val); 189 } 190 191 static void 192 it8712_pnp_enter(lpctag_t tag) 193 { 194 gemini_lpc_softc_t *sc = tag; 195 bus_space_tag_t iot = sc->sc_iot; 196 bus_space_handle_t ioh = sc->sc_ioh; 197 198 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x87); 199 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x01); 200 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x55); 201 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x55); 202 } 203 204 static void 205 it8712_pnp_exit(lpctag_t tag) 206 { 207 gemini_lpc_softc_t *sc = tag; 208 bus_space_tag_t iot = sc->sc_iot; 209 bus_space_handle_t ioh = sc->sc_ioh; 210 211 bus_space_write_1(iot, ioh, IT8712_ADDR, IT8712_CFGCTL); 212 bus_space_write_1(iot, ioh, IT8712_DATA, CFGCTL_WAITKEY); 213 } 214 215 static void * 216 it8712_intr_establish(lpctag_t tag, uint intr, int ipl, int ist, 217 int (*func)(void *), void *arg) 218 { 219 gemini_lpc_softc_t *sc = tag; 220 void *ih; 221 222 ih = gemini_lpchc_intr_establish(sc->sc_lpchctag, intr, ipl, ist, func, arg); 223 224 return ih; 225 } 226 227 static void 228 it8712_intr_disestablish(lpctag_t tag, void *ih) 229 { 230 gemini_lpc_softc_t *sc = tag; 231 232 gemini_lpchc_intr_disestablish(sc->sc_lpchctag, ih); 233 } 234