1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright IBM Corp 2019 3 4 #include <linux/device.h> 5 #include <linux/errno.h> 6 #include <linux/fsi-occ.h> 7 #include <linux/i2c.h> 8 #include <linux/jiffies.h> 9 #include <linux/module.h> 10 #include <linux/sched.h> 11 #include <linux/unaligned.h> 12 13 #include "common.h" 14 15 #define OCC_TIMEOUT_MS 1000 16 #define OCC_CMD_IN_PRG_WAIT_MS 50 17 18 /* OCB (on-chip control bridge - interface to OCC) registers */ 19 #define OCB_DATA1 0x6B035 20 #define OCB_ADDR 0x6B070 21 #define OCB_DATA3 0x6B075 22 23 /* OCC SRAM address space */ 24 #define OCC_SRAM_ADDR_CMD 0xFFFF6000 25 #define OCC_SRAM_ADDR_RESP 0xFFFF7000 26 27 #define OCC_DATA_ATTN 0x20010000 28 29 struct p8_i2c_occ { 30 struct occ occ; 31 struct i2c_client *client; 32 }; 33 34 #define to_p8_i2c_occ(x) container_of((x), struct p8_i2c_occ, occ) 35 36 static int p8_i2c_occ_getscom(struct i2c_client *client, u32 address, u8 *data) 37 { 38 ssize_t rc; 39 __be64 buf; 40 struct i2c_msg msgs[2]; 41 42 /* p8 i2c slave requires shift */ 43 address <<= 1; 44 45 msgs[0].addr = client->addr; 46 msgs[0].flags = client->flags & I2C_M_TEN; 47 msgs[0].len = sizeof(u32); 48 /* address is a scom address; bus-endian */ 49 msgs[0].buf = (char *)&address; 50 51 /* data from OCC is big-endian */ 52 msgs[1].addr = client->addr; 53 msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; 54 msgs[1].len = sizeof(u64); 55 msgs[1].buf = (char *)&buf; 56 57 rc = i2c_transfer(client->adapter, msgs, 2); 58 if (rc < 0) 59 return rc; 60 61 *(u64 *)data = be64_to_cpu(buf); 62 63 return 0; 64 } 65 66 static int p8_i2c_occ_putscom(struct i2c_client *client, u32 address, u8 *data) 67 { 68 u32 buf[3]; 69 ssize_t rc; 70 71 /* p8 i2c slave requires shift */ 72 address <<= 1; 73 74 /* address is bus-endian; data passed through from user as-is */ 75 buf[0] = address; 76 memcpy(&buf[1], &data[4], sizeof(u32)); 77 memcpy(&buf[2], data, sizeof(u32)); 78 79 rc = i2c_master_send(client, (const char *)buf, sizeof(buf)); 80 if (rc < 0) 81 return rc; 82 else if (rc != sizeof(buf)) 83 return -EIO; 84 85 return 0; 86 } 87 88 static int p8_i2c_occ_putscom_u32(struct i2c_client *client, u32 address, 89 u32 data0, u32 data1) 90 { 91 u8 buf[8]; 92 93 memcpy(buf, &data0, 4); 94 memcpy(buf + 4, &data1, 4); 95 96 return p8_i2c_occ_putscom(client, address, buf); 97 } 98 99 static int p8_i2c_occ_putscom_be(struct i2c_client *client, u32 address, 100 u8 *data, size_t len) 101 { 102 __be32 data0 = 0, data1 = 0; 103 104 memcpy(&data0, data, min_t(size_t, len, 4)); 105 if (len > 4) { 106 len -= 4; 107 memcpy(&data1, data + 4, min_t(size_t, len, 4)); 108 } 109 110 return p8_i2c_occ_putscom_u32(client, address, be32_to_cpu(data0), 111 be32_to_cpu(data1)); 112 } 113 114 static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len, 115 void *resp, size_t resp_len) 116 { 117 int i, rc; 118 unsigned long start; 119 u16 data_length; 120 const unsigned long timeout = msecs_to_jiffies(OCC_TIMEOUT_MS); 121 const long wait_time = msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS); 122 struct p8_i2c_occ *ctx = to_p8_i2c_occ(occ); 123 struct i2c_client *client = ctx->client; 124 struct occ_response *or = (struct occ_response *)resp; 125 126 start = jiffies; 127 128 /* set sram address for command */ 129 rc = p8_i2c_occ_putscom_u32(client, OCB_ADDR, OCC_SRAM_ADDR_CMD, 0); 130 if (rc) 131 return rc; 132 133 /* write command (expected to already be BE), we need bus-endian... */ 134 rc = p8_i2c_occ_putscom_be(client, OCB_DATA3, cmd, len); 135 if (rc) 136 return rc; 137 138 /* trigger OCC attention */ 139 rc = p8_i2c_occ_putscom_u32(client, OCB_DATA1, OCC_DATA_ATTN, 0); 140 if (rc) 141 return rc; 142 143 do { 144 /* set sram address for response */ 145 rc = p8_i2c_occ_putscom_u32(client, OCB_ADDR, 146 OCC_SRAM_ADDR_RESP, 0); 147 if (rc) 148 return rc; 149 150 rc = p8_i2c_occ_getscom(client, OCB_DATA3, (u8 *)resp); 151 if (rc) 152 return rc; 153 154 /* wait for OCC */ 155 if (or->return_status == OCC_RESP_CMD_IN_PRG) { 156 rc = -EALREADY; 157 158 if (time_after(jiffies, start + timeout)) 159 break; 160 161 set_current_state(TASK_INTERRUPTIBLE); 162 schedule_timeout(wait_time); 163 } 164 } while (rc); 165 166 /* check the OCC response */ 167 switch (or->return_status) { 168 case OCC_RESP_CMD_IN_PRG: 169 rc = -ETIMEDOUT; 170 break; 171 case OCC_RESP_SUCCESS: 172 rc = 0; 173 break; 174 case OCC_RESP_CMD_INVAL: 175 case OCC_RESP_CMD_LEN_INVAL: 176 case OCC_RESP_DATA_INVAL: 177 case OCC_RESP_CHKSUM_ERR: 178 rc = -EINVAL; 179 break; 180 case OCC_RESP_INT_ERR: 181 case OCC_RESP_BAD_STATE: 182 case OCC_RESP_CRIT_EXCEPT: 183 case OCC_RESP_CRIT_INIT: 184 case OCC_RESP_CRIT_WATCHDOG: 185 case OCC_RESP_CRIT_OCB: 186 case OCC_RESP_CRIT_HW: 187 rc = -EREMOTEIO; 188 break; 189 default: 190 rc = -EPROTO; 191 } 192 193 if (rc < 0) 194 return rc; 195 196 data_length = get_unaligned_be16(&or->data_length); 197 if ((data_length + 7) > resp_len) 198 return -EMSGSIZE; 199 200 /* fetch the rest of the response data */ 201 for (i = 8; i < data_length + 7; i += 8) { 202 rc = p8_i2c_occ_getscom(client, OCB_DATA3, ((u8 *)resp) + i); 203 if (rc) 204 return rc; 205 } 206 207 return 0; 208 } 209 210 static int p8_i2c_occ_probe(struct i2c_client *client) 211 { 212 struct occ *occ; 213 struct p8_i2c_occ *ctx = devm_kzalloc(&client->dev, sizeof(*ctx), 214 GFP_KERNEL); 215 if (!ctx) 216 return -ENOMEM; 217 218 ctx->client = client; 219 occ = &ctx->occ; 220 occ->bus_dev = &client->dev; 221 dev_set_drvdata(&client->dev, occ); 222 223 occ->powr_sample_time_us = 250; 224 occ->poll_cmd_data = 0x10; /* P8 OCC poll data */ 225 occ->send_cmd = p8_i2c_occ_send_cmd; 226 227 return occ_setup(occ); 228 } 229 230 static void p8_i2c_occ_remove(struct i2c_client *client) 231 { 232 struct occ *occ = dev_get_drvdata(&client->dev); 233 234 occ_shutdown(occ); 235 } 236 237 static const struct of_device_id p8_i2c_occ_of_match[] = { 238 { .compatible = "ibm,p8-occ-hwmon" }, 239 {} 240 }; 241 MODULE_DEVICE_TABLE(of, p8_i2c_occ_of_match); 242 243 static struct i2c_driver p8_i2c_occ_driver = { 244 .driver = { 245 .name = "occ-hwmon", 246 .of_match_table = p8_i2c_occ_of_match, 247 }, 248 .probe = p8_i2c_occ_probe, 249 .remove = p8_i2c_occ_remove, 250 }; 251 252 module_i2c_driver(p8_i2c_occ_driver); 253 254 MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>"); 255 MODULE_DESCRIPTION("BMC P8 OCC hwmon driver"); 256 MODULE_LICENSE("GPL"); 257