1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright IBM Corp 2019
4 #include <linux/device.h>
5 #include <linux/errno.h>
6 #include <linux/fsi-occ.h>
8 #include <linux/jiffies.h>
9 #include <linux/module.h>
10 #include <linux/sched.h>
11 #include <asm/unaligned.h>
15 #define OCC_TIMEOUT_MS 1000
16 #define OCC_CMD_IN_PRG_WAIT_MS 50
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
23 /* OCC SRAM address space */
24 #define OCC_SRAM_ADDR_CMD 0xFFFF6000
25 #define OCC_SRAM_ADDR_RESP 0xFFFF7000
27 #define OCC_DATA_ATTN 0x20010000
31 struct i2c_client
*client
;
34 #define to_p8_i2c_occ(x) container_of((x), struct p8_i2c_occ, occ)
36 static int p8_i2c_occ_getscom(struct i2c_client
*client
, u32 address
, u8
*data
)
40 struct i2c_msg msgs
[2];
42 /* p8 i2c slave requires shift */
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
;
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
;
57 rc
= i2c_transfer(client
->adapter
, msgs
, 2);
61 *(u64
*)data
= be64_to_cpu(buf
);
66 static int p8_i2c_occ_putscom(struct i2c_client
*client
, u32 address
, u8
*data
)
71 /* p8 i2c slave requires shift */
74 /* address is bus-endian; data passed through from user as-is */
76 memcpy(&buf
[1], &data
[4], sizeof(u32
));
77 memcpy(&buf
[2], data
, sizeof(u32
));
79 rc
= i2c_master_send(client
, (const char *)buf
, sizeof(buf
));
82 else if (rc
!= sizeof(buf
))
88 static int p8_i2c_occ_putscom_u32(struct i2c_client
*client
, u32 address
,
93 memcpy(buf
, &data0
, 4);
94 memcpy(buf
+ 4, &data1
, 4);
96 return p8_i2c_occ_putscom(client
, address
, buf
);
99 static int p8_i2c_occ_putscom_be(struct i2c_client
*client
, u32 address
,
104 memcpy(&data0
, data
, 4);
105 memcpy(&data1
, data
+ 4, 4);
107 return p8_i2c_occ_putscom_u32(client
, address
, be32_to_cpu(data0
),
111 static int p8_i2c_occ_send_cmd(struct occ
*occ
, u8
*cmd
)
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
;
124 /* set sram address for command */
125 rc
= p8_i2c_occ_putscom_u32(client
, OCB_ADDR
, OCC_SRAM_ADDR_CMD
, 0);
129 /* write command (expected to already be BE), we need bus-endian... */
130 rc
= p8_i2c_occ_putscom_be(client
, OCB_DATA3
, cmd
);
134 /* trigger OCC attention */
135 rc
= p8_i2c_occ_putscom_u32(client
, OCB_DATA1
, OCC_DATA_ATTN
, 0);
140 /* set sram address for response */
141 rc
= p8_i2c_occ_putscom_u32(client
, OCB_ADDR
,
142 OCC_SRAM_ADDR_RESP
, 0);
146 rc
= p8_i2c_occ_getscom(client
, OCB_DATA3
, (u8
*)resp
);
151 if (resp
->return_status
== OCC_RESP_CMD_IN_PRG
) {
154 if (time_after(jiffies
, start
+ timeout
))
157 set_current_state(TASK_INTERRUPTIBLE
);
158 schedule_timeout(wait_time
);
162 /* check the OCC response */
163 switch (resp
->return_status
) {
164 case OCC_RESP_CMD_IN_PRG
:
167 case OCC_RESP_SUCCESS
:
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
:
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
:
192 data_length
= get_unaligned_be16(&resp
->data_length
);
193 if (data_length
> OCC_RESP_DATA_BYTES
)
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
);
206 static int p8_i2c_occ_probe(struct i2c_client
*client
,
207 const struct i2c_device_id
*id
)
210 struct p8_i2c_occ
*ctx
= devm_kzalloc(&client
->dev
, sizeof(*ctx
),
215 ctx
->client
= client
;
217 occ
->bus_dev
= &client
->dev
;
218 dev_set_drvdata(&client
->dev
, occ
);
220 occ
->powr_sample_time_us
= 250;
221 occ
->poll_cmd_data
= 0x10; /* P8 OCC poll data */
222 occ
->send_cmd
= p8_i2c_occ_send_cmd
;
224 return occ_setup(occ
, "p8_occ");
227 static int p8_i2c_occ_remove(struct i2c_client
*client
)
229 struct occ
*occ
= dev_get_drvdata(&client
->dev
);
236 static const struct of_device_id p8_i2c_occ_of_match
[] = {
237 { .compatible
= "ibm,p8-occ-hwmon" },
240 MODULE_DEVICE_TABLE(of
, p8_i2c_occ_of_match
);
242 static struct i2c_driver p8_i2c_occ_driver
= {
243 .class = I2C_CLASS_HWMON
,
246 .of_match_table
= p8_i2c_occ_of_match
,
248 .probe
= p8_i2c_occ_probe
,
249 .remove
= p8_i2c_occ_remove
,
252 module_i2c_driver(p8_i2c_occ_driver
);
254 MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");
255 MODULE_DESCRIPTION("BMC P8 OCC hwmon driver");
256 MODULE_LICENSE("GPL");