1 /* $NetBSD: gemini_lpc.c,v 1.6 2021/08/07 16:18:44 thorpej 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.6 2021/08/07 16:18:44 thorpej 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(device_t, cfdata_t, void *); 31 static void gemini_lpc_attach(device_t, device_t, 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(device_t parent, cfdata_t 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(device_t parent, device_t 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(self, NULL, 116 CFARGS(.search = gemini_lpc_search)); 117 } 118 119 static int 120 gemini_lpc_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 121 { 122 gemini_lpc_softc_t *sc = device_private(parent); 123 gemini_lpc_attach_args_t lpc; 124 125 lpc.lpc_ldn = cf->cf_loc[LPCCF_LDN]; 126 lpc.lpc_addr = cf->cf_loc[LPCCF_ADDR]; 127 lpc.lpc_size = cf->cf_loc[LPCCF_SIZE]; 128 lpc.lpc_intr = cf->cf_loc[LPCCF_INTR]; 129 lpc.lpc_iot = sc->sc_iot; 130 lpc.lpc_tag = sc; 131 lpc.lpc_base = sc->sc_addr; 132 133 if (config_probe(parent, cf, &lpc)) { 134 config_attach(parent, cf, &lpc, gemini_lpc_busprint, CFARGS_NONE); 135 return 0; /* love it */ 136 } 137 138 return UNCONF; /* hate it */ 139 } 140 141 static int 142 gemini_lpc_busprint(void *aux, const char *name) 143 { 144 struct gemini_lpc_attach_args *lpc = aux; 145 146 if (lpc->lpc_ldn != LPCCF_LDN_DEFAULT) 147 aprint_normal(" ldn %d", lpc->lpc_ldn); 148 if (lpc->lpc_addr != LPCCF_ADDR_DEFAULT) 149 aprint_normal(" addr %#lx", lpc->lpc_addr); 150 if (lpc->lpc_size != LPCCF_SIZE_DEFAULT) 151 aprint_normal(" size %#lx", lpc->lpc_size); 152 if (lpc->lpc_intr != LPCCF_INTR_DEFAULT) 153 aprint_normal(" intr %d", lpc->lpc_intr); 154 155 return UNCONF; 156 } 157 158 /* 159 * LPC bus ops 160 */ 161 162 static uint8_t 163 it8712_pnp_read(lpctag_t tag, int ldn, uint index) 164 { 165 gemini_lpc_softc_t *sc = tag; 166 bus_space_tag_t iot = sc->sc_iot; 167 bus_space_handle_t ioh = sc->sc_ioh; 168 169 if (ldn != GEMINI_LPC_LDN_ALL) { 170 bus_space_write_1(iot, ioh, IT8712_ADDR, IT8712_LDN); 171 bus_space_write_1(iot, ioh, IT8712_DATA, ldn); 172 } 173 bus_space_write_1(iot, ioh, IT8712_ADDR, index); 174 return bus_space_read_1(iot, ioh, IT8712_DATA); 175 } 176 177 static void 178 it8712_pnp_write(lpctag_t tag, int ldn, uint index, uint8_t val) 179 { 180 gemini_lpc_softc_t *sc = tag; 181 bus_space_tag_t iot = sc->sc_iot; 182 bus_space_handle_t ioh = sc->sc_ioh; 183 184 if (ldn != GEMINI_LPC_LDN_ALL) { 185 bus_space_write_1(iot, ioh, IT8712_ADDR, IT8712_LDN); 186 bus_space_write_1(iot, ioh, IT8712_DATA, ldn); 187 } 188 bus_space_write_1(iot, ioh, IT8712_ADDR, index); 189 bus_space_write_1(iot, ioh, IT8712_DATA, val); 190 } 191 192 static void 193 it8712_pnp_enter(lpctag_t tag) 194 { 195 gemini_lpc_softc_t *sc = tag; 196 bus_space_tag_t iot = sc->sc_iot; 197 bus_space_handle_t ioh = sc->sc_ioh; 198 199 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x87); 200 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x01); 201 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x55); 202 bus_space_write_1(iot, ioh, IT8712_ADDR, 0x55); 203 } 204 205 static void 206 it8712_pnp_exit(lpctag_t tag) 207 { 208 gemini_lpc_softc_t *sc = tag; 209 bus_space_tag_t iot = sc->sc_iot; 210 bus_space_handle_t ioh = sc->sc_ioh; 211 212 bus_space_write_1(iot, ioh, IT8712_ADDR, IT8712_CFGCTL); 213 bus_space_write_1(iot, ioh, IT8712_DATA, CFGCTL_WAITKEY); 214 } 215 216 static void * 217 it8712_intr_establish(lpctag_t tag, uint intr, int ipl, int ist, 218 int (*func)(void *), void *arg) 219 { 220 gemini_lpc_softc_t *sc = tag; 221 void *ih; 222 223 ih = gemini_lpchc_intr_establish(sc->sc_lpchctag, intr, ipl, ist, func, arg); 224 225 return ih; 226 } 227 228 static void 229 it8712_intr_disestablish(lpctag_t tag, void *ih) 230 { 231 gemini_lpc_softc_t *sc = tag; 232 233 gemini_lpchc_intr_disestablish(sc->sc_lpchctag, ih); 234 } 235