1 /* $NetBSD: shark_iic.c,v 1.3 2025/09/15 13:23:02 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2021 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julian Coleman. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 __KERNEL_RCSID(0, "$NetBSD: shark_iic.c,v 1.3 2025/09/15 13:23:02 thorpej Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 40 #include <dev/ofw/openfirm.h> 41 42 #include <shark/shark/sequoia.h> 43 44 #include <dev/i2c/i2cvar.h> 45 #include <dev/i2c/i2c_bitbang.h> 46 47 #include <arm/cpufunc.h> 48 49 /* define registers on sequoia used by pins */ 50 #define SEQUOIA_1GPIO PMC_GPCR_REG /* reg 0x007 gpio 0-3 */ 51 #define SEQUOIA_2GPIO SEQ2_OGPIOCR_REG /* reg 0x304 gpio 4.8 */ 52 53 /* define pins on sequoia that talk to the DIMM I2C bus */ 54 #define IIC_CLK FOMPCR_M_PCON9 55 #define IIC_DATA_IN_DIR GPCR_M_GPIODIR3 56 #define IIC_DATA_IN GPCR_M_GPIODATA3 57 #define IIC_DATA_OUT_DIR GPIOCR2_M_GPIOBDIR1 58 59 /* logical i2c signals */ 60 #define SHARK_IIC_BIT_SDA 0x01 61 #define SHARK_IIC_BIT_SCL 0x02 62 #define SHARK_IIC_BIT_OUTPUT 0x04 63 #define SHARK_IIC_BIT_INPUT 0x08 64 65 struct sharkiic_softc { 66 device_t sc_dev; 67 struct i2c_controller sc_i2c; 68 }; 69 70 /* I2C bitbanging */ 71 72 static void 73 sequoiaBBInit(void) 74 { 75 uint16_t seqReg; 76 77 sequoiaLock(); 78 79 /* 80 * SCL initialization 81 * - enable pc[9] 82 * - set pin to low (0) 83 */ 84 sequoiaRead(SEQR_SEQPSR3_REG, &seqReg); 85 CLR(seqReg, SEQPSR3_M_PC9PINEN); 86 sequoiaWrite(SEQR_SEQPSR3_REG, seqReg); 87 sequoiaRead(PMC_FOMPCR_REG, &seqReg); 88 SET(seqReg, IIC_CLK); 89 sequoiaWrite(PMC_FOMPCR_REG, seqReg); 90 91 /* 92 * SDA (Output) initialization 93 * - set direction to output 94 * - enable GPIO B1 (sets pin to low) 95 */ 96 sequoiaRead(PMC_GPIOCR2_REG, &seqReg); 97 SET(seqReg, IIC_DATA_OUT_DIR); 98 sequoiaWrite(PMC_GPIOCR2_REG, seqReg); 99 sequoiaRead(SEQR_SEQPSR2_REG, &seqReg); 100 SET(seqReg, SEQPSR2_M_GPIOB1PINEN); 101 sequoiaWrite(SEQR_SEQPSR2_REG, seqReg); 102 103 /* 104 * SDA (Input) initialization 105 * - enable GPIO 106 * - set direction to input 107 */ 108 sequoiaRead(SEQ2_SEQ2PSR_REG, &seqReg); 109 CLR(seqReg, SEQ2PSR_M_GPIOPINEN); 110 sequoiaWrite(SEQ2_SEQ2PSR_REG, seqReg); 111 sequoiaRead(SEQUOIA_1GPIO, &seqReg); 112 CLR(seqReg, IIC_DATA_IN_DIR); 113 sequoiaWrite(SEQUOIA_1GPIO, seqReg); 114 115 sequoiaUnlock(); 116 } 117 118 static void 119 sequoiaBBSetBits(uint32_t bits) 120 { 121 uint16_t seqRegSDA, seqRegSCL; 122 123 sequoiaLock(); 124 125 sequoiaRead(PMC_FOMPCR_REG, &seqRegSCL); 126 sequoiaRead(SEQR_SEQPSR2_REG, &seqRegSDA); 127 128 /* 129 * For SCL and SDA: 130 * - output is the inverse of the desired signal 131 * - the pin enable bit drives the signal 132 */ 133 if (bits & SHARK_IIC_BIT_SCL) { 134 CLR(seqRegSCL, IIC_CLK); 135 } else { 136 SET(seqRegSCL, IIC_CLK); 137 } 138 139 if (bits & SHARK_IIC_BIT_SDA) { 140 CLR(seqRegSDA, SEQPSR2_M_GPIOB1PINEN); 141 } else { 142 SET(seqRegSDA, SEQPSR2_M_GPIOB1PINEN); 143 } 144 145 sequoiaWrite(PMC_FOMPCR_REG, seqRegSCL); 146 sequoiaWrite(SEQR_SEQPSR2_REG, seqRegSDA); 147 148 sequoiaUnlock(); 149 } 150 151 static void 152 sequoiaBBSetDir(uint32_t dir) 153 { 154 uint16_t seqReg; 155 156 sequoiaLock(); 157 158 /* 159 * For direction = Input, set SDA (Output) direction to input, 160 * otherwise we'll only read our own signal on SDA (Input) 161 */ 162 sequoiaRead(PMC_GPIOCR2_REG, &seqReg); 163 if (dir & SHARK_IIC_BIT_OUTPUT) 164 SET(seqReg, IIC_DATA_OUT_DIR); 165 else 166 CLR(seqReg, IIC_DATA_OUT_DIR); 167 sequoiaWrite(PMC_GPIOCR2_REG, seqReg); 168 169 sequoiaUnlock(); 170 } 171 172 static uint32_t 173 sequoiaBBRead(void) 174 { 175 uint16_t seqRegSDA, seqRegSCL; 176 uint32_t bits = 0; 177 178 sequoiaLock(); 179 180 sequoiaRead(SEQUOIA_1GPIO, &seqRegSDA); 181 sequoiaRead(PMC_FOMPCR_REG, &seqRegSCL); 182 183 sequoiaUnlock(); 184 185 if (ISSET(seqRegSDA, IIC_DATA_IN)) 186 bits |= SHARK_IIC_BIT_SDA; 187 if (!ISSET(seqRegSCL, IIC_CLK)) 188 bits |= SHARK_IIC_BIT_SCL; 189 190 return bits; 191 } 192 193 static void 194 sharkiicbb_set_bits(void *cookie, uint32_t bits) 195 { 196 sequoiaBBSetBits(bits); 197 } 198 199 static void 200 sharkiicbb_set_dir(void *cookie, uint32_t dir) 201 { 202 sequoiaBBSetDir(dir); 203 } 204 205 static uint32_t 206 sharkiicbb_read(void *cookie) 207 { 208 return sequoiaBBRead(); 209 } 210 211 static const struct i2c_bitbang_ops sharkiicbb_ops = { 212 .ibo_set_bits = sharkiicbb_set_bits, 213 .ibo_set_dir = sharkiicbb_set_dir, 214 .ibo_read_bits = sharkiicbb_read, 215 .ibo_bits = { 216 [I2C_BIT_SDA] = SHARK_IIC_BIT_SDA, 217 [I2C_BIT_SCL] = SHARK_IIC_BIT_SCL, 218 [I2C_BIT_OUTPUT] = SHARK_IIC_BIT_OUTPUT, 219 [I2C_BIT_INPUT] = SHARK_IIC_BIT_INPUT, 220 }, 221 }; 222 223 /* higher level I2C stuff */ 224 225 static int 226 sharkiic_send_start(void *cookie, int flags) 227 { 228 return (i2c_bitbang_send_start(cookie, flags, &sharkiicbb_ops)); 229 } 230 231 static int 232 sharkiic_send_stop(void *cookie, int flags) 233 { 234 return (i2c_bitbang_send_stop(cookie, flags, &sharkiicbb_ops)); 235 } 236 237 static int 238 sharkiic_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 239 { 240 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, 241 &sharkiicbb_ops)); 242 } 243 244 static int 245 sharkiic_read_byte(void *cookie, uint8_t *valp, int flags) 246 { 247 return (i2c_bitbang_read_byte(cookie, valp, flags, &sharkiicbb_ops)); 248 } 249 250 static int 251 sharkiic_write_byte(void *cookie, uint8_t val, int flags) 252 { 253 return (i2c_bitbang_write_byte(cookie, val, flags, &sharkiicbb_ops)); 254 } 255 256 static int 257 sharkiic_match(device_t parent, cfdata_t match, void *aux) 258 { 259 struct ofbus_attach_args *oba = aux; 260 261 /* "sequoia" interface fills out oba_ofname */ 262 return strcmp(oba->oba_ofname, "dec,dnard-i2c") == 0; 263 } 264 265 static void 266 sharkiic_attach(device_t parent, device_t self, void *aux) 267 { 268 struct sharkiic_softc *sc = device_private(self); 269 270 aprint_naive("\n"); 271 aprint_normal("\n"); 272 273 sequoiaBBInit(); 274 275 iic_tag_init(&sc->sc_i2c); 276 sc->sc_i2c.ic_cookie = sc; 277 sc->sc_i2c.ic_send_start = sharkiic_send_start; 278 sc->sc_i2c.ic_send_stop = sharkiic_send_stop; 279 sc->sc_i2c.ic_initiate_xfer = sharkiic_initiate_xfer; 280 sc->sc_i2c.ic_read_byte = sharkiic_read_byte; 281 sc->sc_i2c.ic_write_byte = sharkiic_write_byte; 282 283 iicbus_attach(self, &sc->sc_i2c); 284 } 285 286 CFATTACH_DECL_NEW(sharkiic, sizeof(struct sharkiic_softc), 287 sharkiic_match, sharkiic_attach, NULL, NULL); 288