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