1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/device.h> 4 #include <linux/errno.h> 5 #include <linux/fsi-occ.h> 6 #include <linux/i2c.h> 7 #include <linux/jiffies.h> 8 #include <linux/module.h> 9 #include <linux/sched.h> 10 #include <asm/unaligned.h> 11 12 #include "common.h" 13 14 #define OCC_TIMEOUT_MS 1000 15 #define OCC_CMD_IN_PRG_WAIT_MS 50 16 17 /* OCB (on-chip control bridge - interface to OCC) registers */ 18 #define OCB_DATA1 0x6B035 19 #define OCB_ADDR 0x6B070 20 #define OCB_DATA3 0x6B075 21 22 /* OCC SRAM address space */ 23 #define OCC_SRAM_ADDR_CMD 0xFFFF6000 24 #define OCC_SRAM_ADDR_RESP 0xFFFF7000 25 26 #define OCC_DATA_ATTN 0x20010000 27 28 struct p8_i2c_occ { 29 struct occ occ; 30 struct i2c_client *client; 31 }; 32 33 #define to_p8_i2c_occ(x) container_of((x), struct p8_i2c_occ, occ) 34 35 static int p8_i2c_occ_getscom(struct i2c_client *client, u32 address, u8 *data) 36 { 37 ssize_t rc; 38 __be64 buf; 39 struct i2c_msg msgs[2]; 40 41 /* p8 i2c slave requires shift */ 42 address <<= 1; 43 44 msgs[0].addr = client->addr; 45 msgs[0].flags = client->flags & I2C_M_TEN; 46 msgs[0].len = sizeof(u32); 47 /* address is a scom address; bus-endian */ 48 msgs[0].buf = (char *)&address; 49 50 /* data from OCC is big-endian */ 51 msgs[1].addr = client->addr; 52 msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; 53 msgs[1].len = sizeof(u64); 54 msgs[1].buf = (char *)&buf; 55 56 rc = i2c_transfer(client->adapter, msgs, 2); 57 if (rc < 0) 58 return rc; 59 60 *(u64 *)data = be64_to_cpu(buf); 61 62 return 0; 63 } 64 65 static int p8_i2c_occ_putscom(struct i2c_client *client, u32 address, u8 *data) 66 { 67 u32 buf[3]; 68 ssize_t rc; 69 70 /* p8 i2c slave requires shift */ 71 address <<= 1; 72 73 /* address is bus-endian; data passed through from user as-is */ 74 buf[0] = address; 75 memcpy(&buf[1], &data[4], sizeof(u32)); 76 memcpy(&buf[2], data, sizeof(u32)); 77 78 rc = i2c_master_send(client, (const char *)buf, sizeof(buf)); 79 if (rc < 0) 80 return rc; 81 else if (rc != sizeof(buf)) 82 return -EIO; 83 84 return 0; 85 } 86 87 static int p8_i2c_occ_putscom_u32(struct i2c_client *client, u32 address, 88 u32 data0, u32 data1) 89 { 90 u8 buf[8]; 91 92 memcpy(buf, &data0, 4); 93 memcpy(buf + 4, &data1, 4); 94 95 return p8_i2c_occ_putscom(client, address, buf); 96 } 97 98 static int p8_i2c_occ_putscom_be(struct i2c_client *client, u32 address, 99 u8 *data) 100 { 101 __be32 data0, data1; 102 103 memcpy(&data0, data, 4); 104 memcpy(&data1, data + 4, 4); 105 106 return p8_i2c_occ_putscom_u32(client, address, be32_to_cpu(data0), 107 be32_to_cpu(data1)); 108 } 109 110 static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd) 111 { 112 int i, rc; 113 unsigned long start; 114 u16 data_length; 115 const unsigned long timeout = msecs_to_jiffies(OCC_TIMEOUT_MS); 116 const long wait_time = msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS); 117 struct p8_i2c_occ *ctx = to_p8_i2c_occ(occ); 118 struct i2c_client *client = ctx->client; 119 struct occ_response *resp = &occ->resp; 120 121 start = jiffies; 122 123 /* set sram address for command */ 124 rc = p8_i2c_occ_putscom_u32(client, OCB_ADDR, OCC_SRAM_ADDR_CMD, 0); 125 if (rc) 126 return rc; 127 128 /* write command (expected to already be BE), we need bus-endian... */ 129 rc = p8_i2c_occ_putscom_be(client, OCB_DATA3, cmd); 130 if (rc) 131 return rc; 132 133 /* trigger OCC attention */ 134 rc = p8_i2c_occ_putscom_u32(client, OCB_DATA1, OCC_DATA_ATTN, 0); 135 if (rc) 136 return rc; 137 138 do { 139 /* set sram address for response */ 140 rc = p8_i2c_occ_putscom_u32(client, OCB_ADDR, 141 OCC_SRAM_ADDR_RESP, 0); 142 if (rc) 143 return rc; 144 145 rc = p8_i2c_occ_getscom(client, OCB_DATA3, (u8 *)resp); 146 if (rc) 147 return rc; 148 149 /* wait for OCC */ 150 if (resp->return_status == OCC_RESP_CMD_IN_PRG) { 151 rc = -EALREADY; 152 153 if (time_after(jiffies, start + timeout)) 154 break; 155 156 set_current_state(TASK_INTERRUPTIBLE); 157 schedule_timeout(wait_time); 158 } 159 } while (rc); 160 161 /* check the OCC response */ 162 switch (resp->return_status) { 163 case OCC_RESP_CMD_IN_PRG: 164 rc = -ETIMEDOUT; 165 break; 166 case OCC_RESP_SUCCESS: 167 rc = 0; 168 break; 169 case OCC_RESP_CMD_INVAL: 170 case OCC_RESP_CMD_LEN_INVAL: 171 case OCC_RESP_DATA_INVAL: 172 case OCC_RESP_CHKSUM_ERR: 173 rc = -EINVAL; 174 break; 175 case OCC_RESP_INT_ERR: 176 case OCC_RESP_BAD_STATE: 177 case OCC_RESP_CRIT_EXCEPT: 178 case OCC_RESP_CRIT_INIT: 179 case OCC_RESP_CRIT_WATCHDOG: 180 case OCC_RESP_CRIT_OCB: 181 case OCC_RESP_CRIT_HW: 182 rc = -EREMOTEIO; 183 break; 184 default: 185 rc = -EPROTO; 186 } 187 188 if (rc < 0) 189 return rc; 190 191 data_length = get_unaligned_be16(&resp->data_length); 192 if (data_length > OCC_RESP_DATA_BYTES) 193 return -EMSGSIZE; 194 195 /* fetch the rest of the response data */ 196 for (i = 8; i < data_length + 7; i += 8) { 197 rc = p8_i2c_occ_getscom(client, OCB_DATA3, ((u8 *)resp) + i); 198 if (rc) 199 return rc; 200 } 201 202 return 0; 203 } 204 205 static int p8_i2c_occ_probe(struct i2c_client *client, 206 const struct i2c_device_id *id) 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 = 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