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 <asm/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 { 116 int i, rc; 117 unsigned long start; 118 u16 data_length; 119 const unsigned long timeout = msecs_to_jiffies(OCC_TIMEOUT_MS); 120 const long wait_time = msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS); 121 struct p8_i2c_occ *ctx = to_p8_i2c_occ(occ); 122 struct i2c_client *client = ctx->client; 123 struct occ_response *resp = &occ->resp; 124 125 start = jiffies; 126 127 /* set sram address for command */ 128 rc = p8_i2c_occ_putscom_u32(client, OCB_ADDR, OCC_SRAM_ADDR_CMD, 0); 129 if (rc) 130 return rc; 131 132 /* write command (expected to already be BE), we need bus-endian... */ 133 rc = p8_i2c_occ_putscom_be(client, OCB_DATA3, cmd, len); 134 if (rc) 135 return rc; 136 137 /* trigger OCC attention */ 138 rc = p8_i2c_occ_putscom_u32(client, OCB_DATA1, OCC_DATA_ATTN, 0); 139 if (rc) 140 return rc; 141 142 do { 143 /* set sram address for response */ 144 rc = p8_i2c_occ_putscom_u32(client, OCB_ADDR, 145 OCC_SRAM_ADDR_RESP, 0); 146 if (rc) 147 return rc; 148 149 rc = p8_i2c_occ_getscom(client, OCB_DATA3, (u8 *)resp); 150 if (rc) 151 return rc; 152 153 /* wait for OCC */ 154 if (resp->return_status == OCC_RESP_CMD_IN_PRG) { 155 rc = -EALREADY; 156 157 if (time_after(jiffies, start + timeout)) 158 break; 159 160 set_current_state(TASK_INTERRUPTIBLE); 161 schedule_timeout(wait_time); 162 } 163 } while (rc); 164 165 /* check the OCC response */ 166 switch (resp->return_status) { 167 case OCC_RESP_CMD_IN_PRG: 168 rc = -ETIMEDOUT; 169 break; 170 case OCC_RESP_SUCCESS: 171 rc = 0; 172 break; 173 case OCC_RESP_CMD_INVAL: 174 case OCC_RESP_CMD_LEN_INVAL: 175 case OCC_RESP_DATA_INVAL: 176 case OCC_RESP_CHKSUM_ERR: 177 rc = -EINVAL; 178 break; 179 case OCC_RESP_INT_ERR: 180 case OCC_RESP_BAD_STATE: 181 case OCC_RESP_CRIT_EXCEPT: 182 case OCC_RESP_CRIT_INIT: 183 case OCC_RESP_CRIT_WATCHDOG: 184 case OCC_RESP_CRIT_OCB: 185 case OCC_RESP_CRIT_HW: 186 rc = -EREMOTEIO; 187 break; 188 default: 189 rc = -EPROTO; 190 } 191 192 if (rc < 0) 193 return rc; 194 195 data_length = get_unaligned_be16(&resp->data_length); 196 if (data_length > OCC_RESP_DATA_BYTES) 197 return -EMSGSIZE; 198 199 /* fetch the rest of the response data */ 200 for (i = 8; i < data_length + 7; i += 8) { 201 rc = p8_i2c_occ_getscom(client, OCB_DATA3, ((u8 *)resp) + i); 202 if (rc) 203 return rc; 204 } 205 206 return 0; 207 } 208 209 static int p8_i2c_occ_probe(struct i2c_client *client) 210 { 211 struct occ *occ; 212 struct p8_i2c_occ *ctx = devm_kzalloc(&client->dev, sizeof(*ctx), 213 GFP_KERNEL); 214 if (!ctx) 215 return -ENOMEM; 216 217 ctx->client = client; 218 occ = &ctx->occ; 219 occ->bus_dev = &client->dev; 220 dev_set_drvdata(&client->dev, occ); 221 222 occ->powr_sample_time_us = 250; 223 occ->poll_cmd_data = 0x10; /* P8 OCC poll data */ 224 occ->send_cmd = p8_i2c_occ_send_cmd; 225 226 return occ_setup(occ, "p8_occ"); 227 } 228 229 static int p8_i2c_occ_remove(struct i2c_client *client) 230 { 231 struct occ *occ = dev_get_drvdata(&client->dev); 232 233 occ_shutdown(occ); 234 235 return 0; 236 } 237 238 static const struct of_device_id p8_i2c_occ_of_match[] = { 239 { .compatible = "ibm,p8-occ-hwmon" }, 240 {} 241 }; 242 MODULE_DEVICE_TABLE(of, p8_i2c_occ_of_match); 243 244 static struct i2c_driver p8_i2c_occ_driver = { 245 .class = I2C_CLASS_HWMON, 246 .driver = { 247 .name = "occ-hwmon", 248 .of_match_table = p8_i2c_occ_of_match, 249 }, 250 .probe_new = p8_i2c_occ_probe, 251 .remove = p8_i2c_occ_remove, 252 }; 253 254 module_i2c_driver(p8_i2c_occ_driver); 255 256 MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>"); 257 MODULE_DESCRIPTION("BMC P8 OCC hwmon driver"); 258 MODULE_LICENSE("GPL"); 259