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