1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) IBM Corporation 2023 */ 3 4 #include <linux/device.h> 5 #include <linux/fsi.h> 6 #include <linux/i2c.h> 7 #include <linux/module.h> 8 #include <linux/mutex.h> 9 10 #include "fsi-master-i2cr.h" 11 12 #define CREATE_TRACE_POINTS 13 #include <trace/events/fsi_master_i2cr.h> 14 15 #define I2CR_ADDRESS_CFAM(a) ((a) >> 2) 16 #define I2CR_INITIAL_PARITY true 17 18 #define I2CR_STATUS_CMD 0x60002 19 #define I2CR_STATUS_ERR BIT_ULL(61) 20 #define I2CR_ERROR_CMD 0x60004 21 #define I2CR_LOG_CMD 0x60008 22 23 static const u8 i2cr_cfam[] = { 24 0xc0, 0x02, 0x0d, 0xa6, 25 0x80, 0x01, 0x10, 0x02, 26 0x80, 0x01, 0x10, 0x02, 27 0x80, 0x01, 0x10, 0x02, 28 0x80, 0x01, 0x80, 0x52, 29 0x80, 0x01, 0x10, 0x02, 30 0x80, 0x01, 0x10, 0x02, 31 0x80, 0x01, 0x10, 0x02, 32 0x80, 0x01, 0x10, 0x02, 33 0x80, 0x01, 0x22, 0x2d, 34 0x00, 0x00, 0x00, 0x00, 35 0xde, 0xad, 0xc0, 0xde 36 }; 37 38 static bool i2cr_check_parity32(u32 v, bool parity) 39 { 40 u32 i; 41 42 for (i = 0; i < 32; ++i) { 43 if (v & (1u << i)) 44 parity = !parity; 45 } 46 47 return parity; 48 } 49 50 static bool i2cr_check_parity64(u64 v) 51 { 52 u32 i; 53 bool parity = I2CR_INITIAL_PARITY; 54 55 for (i = 0; i < 64; ++i) { 56 if (v & (1llu << i)) 57 parity = !parity; 58 } 59 60 return parity; 61 } 62 63 static u32 i2cr_get_command(u32 address, bool parity) 64 { 65 address <<= 1; 66 67 if (i2cr_check_parity32(address, parity)) 68 address |= 1; 69 70 return address; 71 } 72 73 static int i2cr_transfer(struct i2c_client *client, u32 command, u64 *data) 74 { 75 struct i2c_msg msgs[2]; 76 int ret; 77 78 msgs[0].addr = client->addr; 79 msgs[0].flags = 0; 80 msgs[0].len = sizeof(command); 81 msgs[0].buf = (__u8 *)&command; 82 msgs[1].addr = client->addr; 83 msgs[1].flags = I2C_M_RD; 84 msgs[1].len = sizeof(*data); 85 msgs[1].buf = (__u8 *)data; 86 87 ret = i2c_transfer(client->adapter, msgs, 2); 88 if (ret == 2) 89 return 0; 90 91 trace_i2cr_i2c_error(client, command, ret); 92 93 if (ret < 0) 94 return ret; 95 96 return -EIO; 97 } 98 99 static int i2cr_check_status(struct i2c_client *client) 100 { 101 u64 status; 102 int ret; 103 104 ret = i2cr_transfer(client, I2CR_STATUS_CMD, &status); 105 if (ret) 106 return ret; 107 108 if (status & I2CR_STATUS_ERR) { 109 u32 buf[3] = { 0, 0, 0 }; 110 u64 error; 111 u64 log; 112 113 i2cr_transfer(client, I2CR_ERROR_CMD, &error); 114 i2cr_transfer(client, I2CR_LOG_CMD, &log); 115 116 trace_i2cr_status_error(client, status, error, log); 117 118 buf[0] = I2CR_STATUS_CMD; 119 i2c_master_send(client, (const char *)buf, sizeof(buf)); 120 121 buf[0] = I2CR_ERROR_CMD; 122 i2c_master_send(client, (const char *)buf, sizeof(buf)); 123 124 buf[0] = I2CR_LOG_CMD; 125 i2c_master_send(client, (const char *)buf, sizeof(buf)); 126 127 dev_err(&client->dev, "status:%016llx error:%016llx log:%016llx\n", status, error, 128 log); 129 return -EREMOTEIO; 130 } 131 132 trace_i2cr_status(client, status); 133 return 0; 134 } 135 136 int fsi_master_i2cr_read(struct fsi_master_i2cr *i2cr, u32 addr, u64 *data) 137 { 138 u32 command = i2cr_get_command(addr, I2CR_INITIAL_PARITY); 139 int ret; 140 141 mutex_lock(&i2cr->lock); 142 143 ret = i2cr_transfer(i2cr->client, command, data); 144 if (ret) 145 goto unlock; 146 147 ret = i2cr_check_status(i2cr->client); 148 if (ret) 149 goto unlock; 150 151 trace_i2cr_read(i2cr->client, command, data); 152 153 unlock: 154 mutex_unlock(&i2cr->lock); 155 return ret; 156 } 157 EXPORT_SYMBOL_GPL(fsi_master_i2cr_read); 158 159 int fsi_master_i2cr_write(struct fsi_master_i2cr *i2cr, u32 addr, u64 data) 160 { 161 u32 buf[3] = { 0 }; 162 int ret; 163 164 buf[0] = i2cr_get_command(addr, i2cr_check_parity64(data)); 165 memcpy(&buf[1], &data, sizeof(data)); 166 167 mutex_lock(&i2cr->lock); 168 169 ret = i2c_master_send(i2cr->client, (const char *)buf, sizeof(buf)); 170 if (ret == sizeof(buf)) { 171 ret = i2cr_check_status(i2cr->client); 172 if (!ret) 173 trace_i2cr_write(i2cr->client, buf[0], data); 174 } else { 175 trace_i2cr_i2c_error(i2cr->client, buf[0], ret); 176 177 if (ret >= 0) 178 ret = -EIO; 179 } 180 181 mutex_unlock(&i2cr->lock); 182 return ret; 183 } 184 EXPORT_SYMBOL_GPL(fsi_master_i2cr_write); 185 186 static int i2cr_read(struct fsi_master *master, int link, uint8_t id, uint32_t addr, void *val, 187 size_t size) 188 { 189 struct fsi_master_i2cr *i2cr = container_of(master, struct fsi_master_i2cr, master); 190 u64 data; 191 size_t i; 192 int ret; 193 194 if (link || id || (addr & 0xffff0000) || !(size == 1 || size == 2 || size == 4)) 195 return -EINVAL; 196 197 /* 198 * The I2CR doesn't have CFAM or FSI slave address space - only the 199 * engines. In order for this to work with the FSI core, we need to 200 * emulate at minimum the CFAM config table so that the appropriate 201 * engines are discovered. 202 */ 203 if (addr < 0xc00) { 204 if (addr > sizeof(i2cr_cfam) - 4) 205 addr = (addr & 0x3) + (sizeof(i2cr_cfam) - 4); 206 207 memcpy(val, &i2cr_cfam[addr], size); 208 return 0; 209 } 210 211 ret = fsi_master_i2cr_read(i2cr, I2CR_ADDRESS_CFAM(addr), &data); 212 if (ret) 213 return ret; 214 215 /* 216 * FSI core expects up to 4 bytes BE back, while I2CR replied with LE 217 * bytes on the wire. 218 */ 219 for (i = 0; i < size; ++i) 220 ((u8 *)val)[i] = ((u8 *)&data)[7 - i]; 221 222 return 0; 223 } 224 225 static int i2cr_write(struct fsi_master *master, int link, uint8_t id, uint32_t addr, 226 const void *val, size_t size) 227 { 228 struct fsi_master_i2cr *i2cr = container_of(master, struct fsi_master_i2cr, master); 229 u64 data = 0; 230 size_t i; 231 232 if (link || id || (addr & 0xffff0000) || !(size == 1 || size == 2 || size == 4)) 233 return -EINVAL; 234 235 /* I2CR writes to CFAM or FSI slave address are a successful no-op. */ 236 if (addr < 0xc00) 237 return 0; 238 239 /* 240 * FSI core passes up to 4 bytes BE, while the I2CR expects LE bytes on 241 * the wire. 242 */ 243 for (i = 0; i < size; ++i) 244 ((u8 *)&data)[7 - i] = ((u8 *)val)[i]; 245 246 return fsi_master_i2cr_write(i2cr, I2CR_ADDRESS_CFAM(addr), data); 247 } 248 249 static void i2cr_release(struct device *dev) 250 { 251 struct fsi_master_i2cr *i2cr = to_fsi_master_i2cr(to_fsi_master(dev)); 252 253 of_node_put(dev->of_node); 254 255 kfree(i2cr); 256 } 257 258 static int i2cr_probe(struct i2c_client *client) 259 { 260 struct fsi_master_i2cr *i2cr; 261 int ret; 262 263 i2cr = kzalloc_obj(*i2cr); 264 if (!i2cr) 265 return -ENOMEM; 266 267 /* Only one I2CR on any given I2C bus (fixed I2C device address) */ 268 i2cr->master.idx = client->adapter->nr; 269 dev_set_name(&i2cr->master.dev, "i2cr%d", i2cr->master.idx); 270 i2cr->master.dev.parent = &client->dev; 271 i2cr->master.dev.of_node = of_node_get(dev_of_node(&client->dev)); 272 i2cr->master.dev.release = i2cr_release; 273 274 i2cr->master.n_links = 1; 275 i2cr->master.read = i2cr_read; 276 i2cr->master.write = i2cr_write; 277 278 mutex_init(&i2cr->lock); 279 i2cr->client = client; 280 281 ret = fsi_master_register(&i2cr->master); 282 if (ret) 283 return ret; 284 285 i2c_set_clientdata(client, i2cr); 286 return 0; 287 } 288 289 static void i2cr_remove(struct i2c_client *client) 290 { 291 struct fsi_master_i2cr *i2cr = i2c_get_clientdata(client); 292 293 fsi_master_unregister(&i2cr->master); 294 } 295 296 static const struct of_device_id i2cr_ids[] = { 297 { .compatible = "ibm,i2cr-fsi-master" }, 298 { } 299 }; 300 MODULE_DEVICE_TABLE(of, i2cr_ids); 301 302 static struct i2c_driver i2cr_driver = { 303 .probe = i2cr_probe, 304 .remove = i2cr_remove, 305 .driver = { 306 .name = "fsi-master-i2cr", 307 .of_match_table = i2cr_ids, 308 }, 309 }; 310 311 module_i2c_driver(i2cr_driver) 312 313 MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>"); 314 MODULE_DESCRIPTION("IBM I2C Responder virtual FSI master driver"); 315 MODULE_LICENSE("GPL"); 316