1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2021-2023 Microchip 4 */ 5 6 #include <assert.h> 7 #include <drivers/clk.h> 8 #include <drivers/clk_dt.h> 9 #include <drivers/i2c.h> 10 #include <io.h> 11 #include <kernel/dt.h> 12 #include <kernel/dt_driver.h> 13 #include <libfdt.h> 14 #include <matrix.h> 15 #include <platform_config.h> 16 #include <string.h> 17 18 #define TWIHS_CR 0x0 19 #define TWIHS_CR_SWRST BIT(7) 20 #define TWIHS_CR_SVDIS BIT(5) 21 #define TWIHS_CR_MSEN BIT(2) 22 #define TWIHS_CR_STOP BIT(1) 23 #define TWIHS_CR_START BIT(0) 24 25 #define TWIHS_MMR 0x4 26 #define TWIHS_MMR_DADR_SHIFT 16 27 #define TWIHS_MMR_DADR_MASK 0x7F 28 #define TWIHS_MMR_MREAD BIT32(12) 29 30 #define TWIHS_CWGR 0x10 31 #define TWIHS_CWGR_HOLD_SHIFT 24 32 #define TWIHS_CWGR_HOLD_MAX 0x1F 33 #define TWIHS_CWGR_CKDIV_SHIFT 16 34 #define TWIHS_CWGR_CKDIV_MAX 0x7 35 #define TWIHS_CWGR_CHDIV_SHIFT 8 36 37 #define TWIHS_CKSRC BIT32(20) 38 39 #define TWIHS_SR 0x20 40 #define TWIHS_SR_NACK BIT32(8) 41 #define TWIHS_SR_TXRDY BIT32(2) 42 #define TWIHS_SR_RXRDY BIT32(1) 43 #define TWIHS_SR_TXCOMP BIT32(0) 44 45 #define TWIHS_RHR 0x30 46 #define TWIHS_THR 0x34 47 48 #define TWIHS_WPMR 0xE4 49 #define TWIHS_WPMR_WPKEY SHIFT_U32(0x545749, 8) 50 51 #define I2C_BUS_FREQ 400000 52 53 struct atmel_i2c { 54 uint32_t sda_hold_time; 55 vaddr_t base; 56 struct clk *clk; 57 struct i2c_ctrl i2c_ctrl; 58 }; 59 60 static struct atmel_i2c *atmel_i2c_from_i2c_ctrl(struct i2c_ctrl *i2c_ctrl) 61 { 62 return container_of(i2c_ctrl, struct atmel_i2c, i2c_ctrl); 63 } 64 65 static TEE_Result atmel_i2c_send_one_byte(struct atmel_i2c *i2c, uint8_t byte) 66 { 67 uint32_t sr = 0; 68 69 io_write32(i2c->base + TWIHS_THR, byte); 70 71 while (true) { 72 sr = io_read32(i2c->base + TWIHS_SR); 73 if (sr & TWIHS_SR_NACK) { 74 EMSG("I2C received NACK while writing"); 75 return TEE_ERROR_GENERIC; 76 } 77 if (sr & TWIHS_SR_TXRDY) 78 break; 79 } 80 81 return TEE_SUCCESS; 82 } 83 84 static void atmel_i2c_wait_txcomp(struct atmel_i2c *i2c) 85 { 86 uint32_t sr = 0; 87 88 while (true) { 89 sr = io_read32(i2c->base + TWIHS_SR); 90 if (sr & TWIHS_SR_TXCOMP) 91 return; 92 } 93 } 94 95 static void atmel_i2c_send_start(struct atmel_i2c *i2c) 96 { 97 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_START); 98 } 99 100 static void atmel_i2c_send_stop(struct atmel_i2c *i2c) 101 { 102 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_STOP); 103 } 104 105 static TEE_Result atmel_i2c_write_data_no_stop(struct i2c_dev *i2c_dev, 106 const uint8_t *buf, size_t len) 107 { 108 size_t i = 0; 109 TEE_Result res = TEE_ERROR_GENERIC; 110 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl); 111 uint32_t mmr = SHIFT_U32(i2c_dev->addr, TWIHS_MMR_DADR_SHIFT); 112 113 io_write32(i2c->base + TWIHS_MMR, mmr); 114 115 for (i = 0; i < len; i++) { 116 res = atmel_i2c_send_one_byte(i2c, buf[i]); 117 if (res) 118 return res; 119 } 120 121 return TEE_SUCCESS; 122 } 123 124 static TEE_Result atmel_i2c_write_data(struct i2c_dev *i2c_dev, 125 const uint8_t *buf, size_t len) 126 { 127 TEE_Result res = TEE_ERROR_GENERIC; 128 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl); 129 130 res = atmel_i2c_write_data_no_stop(i2c_dev, buf, len); 131 if (res) 132 return res; 133 134 atmel_i2c_send_stop(i2c); 135 atmel_i2c_wait_txcomp(i2c); 136 137 return TEE_SUCCESS; 138 } 139 140 static TEE_Result atmel_i2c_recv_one_byte(struct atmel_i2c *i2c, 141 uint8_t *byte) 142 { 143 uint32_t sr = 0; 144 145 while (true) { 146 sr = io_read32(i2c->base + TWIHS_SR); 147 if (sr & TWIHS_SR_NACK) { 148 EMSG("I2C received NACK while reading"); 149 return TEE_ERROR_GENERIC; 150 } 151 if (sr & TWIHS_SR_RXRDY) 152 break; 153 } 154 155 *byte = io_read32(i2c->base + TWIHS_RHR); 156 157 return TEE_SUCCESS; 158 } 159 160 static TEE_Result atmel_i2c_read_data(struct i2c_dev *i2c_dev, uint8_t *buf, 161 size_t len) 162 { 163 size_t i = 0; 164 TEE_Result res = TEE_ERROR_GENERIC; 165 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl); 166 uint32_t mmr = TWIHS_MMR_MREAD | SHIFT_U32(i2c_dev->addr, 167 TWIHS_MMR_DADR_SHIFT); 168 169 io_write32(i2c->base + TWIHS_MMR, mmr); 170 171 atmel_i2c_send_start(i2c); 172 173 for (i = 0; i < len; i++) { 174 if (i == len - 1) 175 atmel_i2c_send_stop(i2c); 176 177 res = atmel_i2c_recv_one_byte(i2c, &buf[i]); 178 if (res) 179 return res; 180 } 181 182 atmel_i2c_wait_txcomp(i2c); 183 184 return TEE_SUCCESS; 185 } 186 187 static TEE_Result atmel_i2c_smbus(struct i2c_dev *i2c_dev, 188 enum i2c_smbus_dir dir, 189 enum i2c_smbus_protocol proto __unused, 190 uint8_t cmd_code, 191 uint8_t buf[I2C_SMBUS_MAX_BUF_SIZE], 192 size_t len) 193 { 194 TEE_Result res = TEE_ERROR_GENERIC; 195 196 /* Send command code first */ 197 res = atmel_i2c_write_data_no_stop(i2c_dev, &cmd_code, 1); 198 if (res) 199 return res; 200 201 if (dir == I2C_SMBUS_READ) 202 return atmel_i2c_read_data(i2c_dev, buf, len); 203 else 204 return atmel_i2c_write_data(i2c_dev, buf, len); 205 } 206 207 static unsigned int flsi(unsigned int val) 208 { 209 if (val == 0) 210 return 0; 211 212 return sizeof(unsigned int) * 8 - __builtin_clz(val); 213 } 214 215 static TEE_Result atmel_i2c_init_clk(struct atmel_i2c *i2c) 216 { 217 long div = 0; 218 long hold = 0; 219 uint32_t cwgr = 0; 220 uint32_t cxdiv = 0; 221 uint32_t ckdiv = 0; 222 unsigned long clk = clk_get_rate(i2c->clk); 223 224 /* 225 * Since we will configure both CHDIV and CLDIV with the same value 226 * use 2 * clk 227 */ 228 div = UDIV_ROUND_NEAREST(clk, 2 * I2C_BUS_FREQ) - 3; 229 if (div < 0) 230 div = 0; 231 232 /* CHDIV/CLDIV are on 8 bits, CKDIV on 3 bits */ 233 ckdiv = flsi(div >> 8); 234 if (ckdiv > TWIHS_CWGR_CKDIV_MAX) { 235 EMSG("CKDIV value too large"); 236 return TEE_ERROR_BAD_PARAMETERS; 237 } 238 cxdiv = div >> ckdiv; 239 240 if (i2c->sda_hold_time) { 241 /* hold_time = (HOLD + 3) x tperipheral clock */ 242 hold = UDIV_ROUND_NEAREST(i2c->sda_hold_time * clk, 1000000000); 243 hold -= 3; 244 if (hold < 0 || hold > TWIHS_CWGR_HOLD_MAX) { 245 EMSG("Incorrect hold value"); 246 return TEE_ERROR_BAD_PARAMETERS; 247 } 248 249 cwgr |= hold << TWIHS_CWGR_HOLD_SHIFT; 250 } 251 252 cwgr |= ckdiv << TWIHS_CWGR_CKDIV_SHIFT; 253 /* CHDIV == CLDIV */ 254 cwgr |= cxdiv << TWIHS_CWGR_CHDIV_SHIFT; 255 cwgr |= cxdiv; 256 io_write32(i2c->base + TWIHS_CWGR, cwgr); 257 258 return TEE_SUCCESS; 259 } 260 261 static TEE_Result atmel_i2c_init_hw(struct atmel_i2c *i2c) 262 { 263 /* Unlock TWIHS IP */ 264 io_write32(i2c->base + TWIHS_WPMR, TWIHS_WPMR_WPKEY); 265 266 /* Configure master mode */ 267 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SWRST); 268 269 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SVDIS); 270 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_MSEN); 271 272 return atmel_i2c_init_clk(i2c); 273 } 274 275 static const struct i2c_ctrl_ops atmel_i2c_ops = { 276 .read = atmel_i2c_read_data, 277 .write = atmel_i2c_write_data, 278 .smbus = atmel_i2c_smbus, 279 }; 280 281 static TEE_Result atmel_i2c_get_dt_i2c(struct dt_pargs *args, void *data, 282 struct i2c_dev **out_device) 283 { 284 struct i2c_dev *i2c_dev = NULL; 285 struct i2c_ctrl *i2c_ctrl = data; 286 287 i2c_dev = i2c_create_dev(i2c_ctrl, args->fdt, args->consumer_node); 288 if (!i2c_dev) 289 return TEE_ERROR_OUT_OF_MEMORY; 290 291 *out_device = i2c_dev; 292 293 return TEE_SUCCESS; 294 } 295 296 static TEE_Result atmel_i2c_node_probe(const void *fdt, int node, 297 const void *compat_data __unused) 298 { 299 size_t size = 0; 300 const uint32_t *cuint = 0; 301 unsigned int matrix_id = 0; 302 struct i2c_ctrl *i2c_ctrl = NULL; 303 struct atmel_i2c *atmel_i2c = NULL; 304 TEE_Result res = TEE_ERROR_GENERIC; 305 int status = fdt_get_status(fdt, node); 306 307 if (status != DT_STATUS_OK_SEC) 308 return TEE_SUCCESS; 309 310 atmel_i2c = calloc(1, sizeof(struct atmel_i2c)); 311 if (!atmel_i2c) 312 return TEE_ERROR_OUT_OF_MEMORY; 313 314 i2c_ctrl = &atmel_i2c->i2c_ctrl; 315 i2c_ctrl->ops = &atmel_i2c_ops; 316 317 res = clk_dt_get_by_index(fdt, node, 0, &atmel_i2c->clk); 318 if (res) 319 goto err_free; 320 321 res = matrix_dt_get_id(fdt, node, &matrix_id); 322 if (res) 323 goto err_free; 324 325 if (dt_map_dev(fdt, node, &atmel_i2c->base, &size, DT_MAP_AUTO) < 0) { 326 res = TEE_ERROR_GENERIC; 327 goto err_free; 328 } 329 330 matrix_configure_periph_secure(matrix_id); 331 332 cuint = fdt_getprop(fdt, node, "i2c-sda-hold-time-ns", NULL); 333 if (cuint) 334 atmel_i2c->sda_hold_time = fdt32_to_cpu(*cuint); 335 336 clk_enable(atmel_i2c->clk); 337 338 res = atmel_i2c_init_hw(atmel_i2c); 339 if (res) 340 goto err_clk_disable; 341 342 res = i2c_register_provider(fdt, node, atmel_i2c_get_dt_i2c, i2c_ctrl); 343 if (res) 344 goto err_clk_disable; 345 346 return TEE_SUCCESS; 347 348 err_clk_disable: 349 clk_disable(atmel_i2c->clk); 350 err_free: 351 free(atmel_i2c); 352 353 return res; 354 } 355 356 static const struct dt_device_match atmel_i2c_match_table[] = { 357 { .compatible = "atmel,sama5d2-i2c" }, 358 { } 359 }; 360 361 DEFINE_DT_DRIVER(atmel_i2c_dt_driver) = { 362 .name = "atmel_i2c", 363 .type = DT_DRIVER_NOTYPE, 364 .match_table = atmel_i2c_match_table, 365 .probe = atmel_i2c_node_probe, 366 }; 367