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_driver.h> 12 #include <libfdt.h> 13 #include <matrix.h> 14 #include <platform_config.h> 15 #include <string.h> 16 17 #define TWIHS_CR 0x0 18 #define TWIHS_CR_SWRST BIT(7) 19 #define TWIHS_CR_SVDIS BIT(5) 20 #define TWIHS_CR_MSEN BIT(2) 21 #define TWIHS_CR_STOP BIT(1) 22 #define TWIHS_CR_START BIT(0) 23 24 #define TWIHS_MMR 0x4 25 #define TWIHS_MMR_DADR_SHIFT 16 26 #define TWIHS_MMR_DADR_MASK 0x7F 27 #define TWIHS_MMR_MREAD BIT32(12) 28 29 #define TWIHS_CWGR 0x10 30 #define TWIHS_CWGR_HOLD_SHIFT 24 31 #define TWIHS_CWGR_HOLD_MAX 0x1F 32 #define TWIHS_CWGR_CKDIV_SHIFT 16 33 #define TWIHS_CWGR_CKDIV_MAX 0x7 34 #define TWIHS_CWGR_CHDIV_SHIFT 8 35 36 #define TWIHS_CKSRC BIT32(20) 37 38 #define TWIHS_SR 0x20 39 #define TWIHS_SR_NACK BIT32(8) 40 #define TWIHS_SR_TXRDY BIT32(2) 41 #define TWIHS_SR_RXRDY BIT32(1) 42 #define TWIHS_SR_TXCOMP BIT32(0) 43 44 #define TWIHS_RHR 0x30 45 #define TWIHS_THR 0x34 46 47 #define TWIHS_WPMR 0xE4 48 #define TWIHS_WPMR_WPKEY SHIFT_U32(0x545749, 8) 49 50 #define I2C_BUS_FREQ 400000 51 52 struct atmel_i2c { 53 uint32_t sda_hold_time; 54 vaddr_t base; 55 struct clk *clk; 56 struct i2c_ctrl i2c_ctrl; 57 }; 58 59 static struct atmel_i2c *atmel_i2c_from_i2c_ctrl(struct i2c_ctrl *i2c_ctrl) 60 { 61 return container_of(i2c_ctrl, struct atmel_i2c, i2c_ctrl); 62 } 63 64 static TEE_Result atmel_i2c_send_one_byte(struct atmel_i2c *i2c, uint8_t byte) 65 { 66 uint32_t sr = 0; 67 68 io_write32(i2c->base + TWIHS_THR, byte); 69 70 while (true) { 71 sr = io_read32(i2c->base + TWIHS_SR); 72 if (sr & TWIHS_SR_NACK) { 73 EMSG("I2C received NACK while writing"); 74 return TEE_ERROR_GENERIC; 75 } 76 if (sr & TWIHS_SR_TXRDY) 77 break; 78 } 79 80 return TEE_SUCCESS; 81 } 82 83 static void atmel_i2c_wait_txcomp(struct atmel_i2c *i2c) 84 { 85 uint32_t sr = 0; 86 87 while (true) { 88 sr = io_read32(i2c->base + TWIHS_SR); 89 if (sr & TWIHS_SR_TXCOMP) 90 return; 91 } 92 } 93 94 static void atmel_i2c_send_start(struct atmel_i2c *i2c) 95 { 96 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_START); 97 } 98 99 static void atmel_i2c_send_stop(struct atmel_i2c *i2c) 100 { 101 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_STOP); 102 } 103 104 static TEE_Result atmel_i2c_write_data_no_stop(struct i2c_dev *i2c_dev, 105 const uint8_t *buf, size_t len) 106 { 107 size_t i = 0; 108 TEE_Result res = TEE_ERROR_GENERIC; 109 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl); 110 uint32_t mmr = SHIFT_U32(i2c_dev->addr, TWIHS_MMR_DADR_SHIFT); 111 112 io_write32(i2c->base + TWIHS_MMR, mmr); 113 114 for (i = 0; i < len; i++) { 115 res = atmel_i2c_send_one_byte(i2c, buf[i]); 116 if (res) 117 return res; 118 } 119 120 return TEE_SUCCESS; 121 } 122 123 static TEE_Result atmel_i2c_write_data(struct i2c_dev *i2c_dev, 124 const uint8_t *buf, size_t len) 125 { 126 TEE_Result res = TEE_ERROR_GENERIC; 127 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl); 128 129 res = atmel_i2c_write_data_no_stop(i2c_dev, buf, len); 130 if (res) 131 return res; 132 133 atmel_i2c_send_stop(i2c); 134 atmel_i2c_wait_txcomp(i2c); 135 136 return TEE_SUCCESS; 137 } 138 139 static TEE_Result atmel_i2c_recv_one_byte(struct atmel_i2c *i2c, 140 uint8_t *byte) 141 { 142 uint32_t sr = 0; 143 144 while (true) { 145 sr = io_read32(i2c->base + TWIHS_SR); 146 if (sr & TWIHS_SR_NACK) { 147 EMSG("I2C received NACK while reading"); 148 return TEE_ERROR_GENERIC; 149 } 150 if (sr & TWIHS_SR_RXRDY) 151 break; 152 } 153 154 *byte = io_read32(i2c->base + TWIHS_RHR); 155 156 return TEE_SUCCESS; 157 } 158 159 static TEE_Result atmel_i2c_read_data(struct i2c_dev *i2c_dev, uint8_t *buf, 160 size_t len) 161 { 162 size_t i = 0; 163 TEE_Result res = TEE_ERROR_GENERIC; 164 struct atmel_i2c *i2c = atmel_i2c_from_i2c_ctrl(i2c_dev->ctrl); 165 uint32_t mmr = TWIHS_MMR_MREAD | SHIFT_U32(i2c_dev->addr, 166 TWIHS_MMR_DADR_SHIFT); 167 168 io_write32(i2c->base + TWIHS_MMR, mmr); 169 170 atmel_i2c_send_start(i2c); 171 172 for (i = 0; i < len; i++) { 173 if (i == len - 1) 174 atmel_i2c_send_stop(i2c); 175 176 res = atmel_i2c_recv_one_byte(i2c, &buf[i]); 177 if (res) 178 return res; 179 } 180 181 atmel_i2c_wait_txcomp(i2c); 182 183 return TEE_SUCCESS; 184 } 185 186 static TEE_Result atmel_i2c_smbus(struct i2c_dev *i2c_dev, 187 enum i2c_smbus_dir dir, 188 enum i2c_smbus_protocol proto __unused, 189 uint8_t cmd_code, 190 uint8_t buf[I2C_SMBUS_MAX_BUF_SIZE], 191 size_t len) 192 { 193 TEE_Result res = TEE_ERROR_GENERIC; 194 195 /* Send command code first */ 196 res = atmel_i2c_write_data_no_stop(i2c_dev, &cmd_code, 1); 197 if (res) 198 return res; 199 200 if (dir == I2C_SMBUS_READ) 201 return atmel_i2c_read_data(i2c_dev, buf, len); 202 else 203 return atmel_i2c_write_data(i2c_dev, buf, len); 204 } 205 206 static unsigned int flsi(unsigned int val) 207 { 208 if (val == 0) 209 return 0; 210 211 return sizeof(unsigned int) * 8 - __builtin_clz(val); 212 } 213 214 static TEE_Result atmel_i2c_init_clk(struct atmel_i2c *i2c) 215 { 216 long div = 0; 217 long hold = 0; 218 uint32_t cwgr = 0; 219 uint32_t cxdiv = 0; 220 uint32_t ckdiv = 0; 221 unsigned long clk = clk_get_rate(i2c->clk); 222 223 /* 224 * Since we will configure both CHDIV and CLDIV with the same value 225 * use 2 * clk 226 */ 227 div = UDIV_ROUND_NEAREST(clk, 2 * I2C_BUS_FREQ) - 3; 228 if (div < 0) 229 div = 0; 230 231 /* CHDIV/CLDIV are on 8 bits, CKDIV on 3 bits */ 232 ckdiv = flsi(div >> 8); 233 if (ckdiv > TWIHS_CWGR_CKDIV_MAX) { 234 EMSG("CKDIV value too large"); 235 return TEE_ERROR_BAD_PARAMETERS; 236 } 237 cxdiv = div >> ckdiv; 238 239 if (i2c->sda_hold_time) { 240 /* hold_time = (HOLD + 3) x tperipheral clock */ 241 hold = UDIV_ROUND_NEAREST(i2c->sda_hold_time * clk, 1000000000); 242 hold -= 3; 243 if (hold < 0 || hold > TWIHS_CWGR_HOLD_MAX) { 244 EMSG("Incorrect hold value"); 245 return TEE_ERROR_BAD_PARAMETERS; 246 } 247 248 cwgr |= hold << TWIHS_CWGR_HOLD_SHIFT; 249 } 250 251 cwgr |= ckdiv << TWIHS_CWGR_CKDIV_SHIFT; 252 /* CHDIV == CLDIV */ 253 cwgr |= cxdiv << TWIHS_CWGR_CHDIV_SHIFT; 254 cwgr |= cxdiv; 255 io_write32(i2c->base + TWIHS_CWGR, cwgr); 256 257 return TEE_SUCCESS; 258 } 259 260 static TEE_Result atmel_i2c_init_hw(struct atmel_i2c *i2c) 261 { 262 /* Unlock TWIHS IP */ 263 io_write32(i2c->base + TWIHS_WPMR, TWIHS_WPMR_WPKEY); 264 265 /* Configure master mode */ 266 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SWRST); 267 268 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_SVDIS); 269 io_write32(i2c->base + TWIHS_CR, TWIHS_CR_MSEN); 270 271 return atmel_i2c_init_clk(i2c); 272 } 273 274 static const struct i2c_ctrl_ops atmel_i2c_ops = { 275 .read = atmel_i2c_read_data, 276 .write = atmel_i2c_write_data, 277 .smbus = atmel_i2c_smbus, 278 }; 279 280 static struct i2c_dev *atmel_i2c_get_dt_i2c(struct dt_driver_phandle_args *a, 281 void *data, TEE_Result *res) 282 { 283 struct i2c_dev *i2c_dev = NULL; 284 struct i2c_ctrl *i2c_ctrl = data; 285 286 i2c_dev = i2c_create_dev(i2c_ctrl, a->fdt, a->phandle_node); 287 if (!i2c_dev) { 288 *res = TEE_ERROR_OUT_OF_MEMORY; 289 return NULL; 290 } 291 292 *res = TEE_SUCCESS; 293 return i2c_dev; 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