1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019 Nuvoton Technology corporation
4 #include <linux/bitfield.h>
6 #include <linux/interrupt.h>
7 #include <linux/jiffies.h>
8 #include <linux/module.h>
10 #include <linux/peci.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
13 #include <linux/reset.h>
16 #define NPCM_INTCR3_OFFSET 0x9C
17 #define NPCM_INTCR3_PECIVSEL BIT(19)
19 /* NPCM PECI Registers */
20 #define NPCM_PECI_CTL_STS 0x00
21 #define NPCM_PECI_RD_LENGTH 0x04
22 #define NPCM_PECI_ADDR 0x08
23 #define NPCM_PECI_CMD 0x0C
24 #define NPCM_PECI_CTL2 0x10
25 #define NPCM_PECI_WR_LENGTH 0x1C
26 #define NPCM_PECI_PDDR 0x2C
27 #define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4))
29 #define NPCM_PECI_MAX_REG 0x200
31 /* NPCM_PECI_CTL_STS - 0x00 : Control Register */
32 #define NPCM_PECI_CTRL_DONE_INT_EN BIT(6)
33 #define NPCM_PECI_CTRL_ABRT_ERR BIT(4)
34 #define NPCM_PECI_CTRL_CRC_ERR BIT(3)
35 #define NPCM_PECI_CTRL_DONE BIT(1)
36 #define NPCM_PECI_CTRL_START_BUSY BIT(0)
38 /* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */
39 #define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0)
41 /* NPCM_PECI_CMD - 0x10 : Command Register */
42 #define NPCM_PECI_CTL2_MASK GENMASK(7, 6)
44 /* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */
45 #define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0)
47 /* NPCM_PECI_PDDR - 0x2C : Command Register */
48 #define NPCM_PECI_PDDR_MASK GENMASK(4, 0)
50 #define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \
51 NPCM_PECI_CTRL_CRC_ERR | \
54 #define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC (50 * USEC_PER_MSEC)
55 #define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC (10 * USEC_PER_MSEC)
56 #define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000
57 #define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000
58 #define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15
59 #define NPCM_PECI_PULL_DOWN_DEFAULT 0
63 struct completion xfer_complete
;
64 struct regmap
*regmap
;
66 spinlock_t lock
; /* to sync completion status handling */
67 struct peci_controller
*controller
;
73 static int npcm_peci_xfer(struct peci_controller
*controller
, u8 addr
, struct peci_request
*req
)
75 struct npcm_peci
*priv
= dev_get_drvdata(controller
->dev
.parent
);
76 unsigned long timeout
= msecs_to_jiffies(priv
->cmd_timeout_ms
);
81 /* Check command sts and bus idle state */
82 ret
= regmap_read_poll_timeout(priv
->regmap
, NPCM_PECI_CTL_STS
, cmd_sts
,
83 !(cmd_sts
& NPCM_PECI_CTRL_START_BUSY
),
84 NPCM_PECI_IDLE_CHECK_INTERVAL_USEC
,
85 NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC
);
87 return ret
; /* -ETIMEDOUT */
89 spin_lock_irq(&priv
->lock
);
90 reinit_completion(&priv
->xfer_complete
);
92 regmap_write(priv
->regmap
, NPCM_PECI_ADDR
, addr
);
93 regmap_write(priv
->regmap
, NPCM_PECI_RD_LENGTH
, NPCM_PECI_WR_LEN_MASK
& req
->rx
.len
);
94 regmap_write(priv
->regmap
, NPCM_PECI_WR_LENGTH
, NPCM_PECI_WR_LEN_MASK
& req
->tx
.len
);
97 regmap_write(priv
->regmap
, NPCM_PECI_CMD
, req
->tx
.buf
[0]);
99 for (i
= 0; i
< (req
->tx
.len
- 1); i
++)
100 regmap_write(priv
->regmap
, NPCM_PECI_DAT_INOUT(i
), req
->tx
.buf
[i
+ 1]);
103 #if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
104 dev_dbg(priv
->dev
, "addr : %#02x, tx.len : %#02x, rx.len : %#02x\n",
105 addr
, req
->tx
.len
, req
->rx
.len
);
106 print_hex_dump_bytes("TX : ", DUMP_PREFIX_NONE
, req
->tx
.buf
, req
->tx
.len
);
110 regmap_update_bits(priv
->regmap
, NPCM_PECI_CTL_STS
, NPCM_PECI_CTRL_START_BUSY
,
111 NPCM_PECI_CTRL_START_BUSY
);
113 spin_unlock_irq(&priv
->lock
);
115 ret
= wait_for_completion_interruptible_timeout(&priv
->xfer_complete
, timeout
);
120 dev_dbg(priv
->dev
, "timeout waiting for a response\n");
124 spin_lock_irq(&priv
->lock
);
126 if (priv
->status
!= NPCM_PECI_CTRL_DONE
) {
127 spin_unlock_irq(&priv
->lock
);
128 dev_dbg(priv
->dev
, "no valid response, status: %#02x\n", priv
->status
);
132 regmap_write(priv
->regmap
, NPCM_PECI_CMD
, 0);
134 for (i
= 0; i
< req
->rx
.len
; i
++) {
135 regmap_read(priv
->regmap
, NPCM_PECI_DAT_INOUT(i
), &msg_rd
);
136 req
->rx
.buf
[i
] = (u8
)msg_rd
;
139 spin_unlock_irq(&priv
->lock
);
141 #if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
142 print_hex_dump_bytes("RX : ", DUMP_PREFIX_NONE
, req
->rx
.buf
, req
->rx
.len
);
147 static irqreturn_t
npcm_peci_irq_handler(int irq
, void *arg
)
149 struct npcm_peci
*priv
= arg
;
153 spin_lock(&priv
->lock
);
154 regmap_read(priv
->regmap
, NPCM_PECI_CTL_STS
, &status
);
155 priv
->status
|= (status
& NPCM_PECI_INT_MASK
);
157 if (status
& NPCM_PECI_CTRL_CRC_ERR
)
158 status_ack
|= NPCM_PECI_CTRL_CRC_ERR
;
160 if (status
& NPCM_PECI_CTRL_ABRT_ERR
)
161 status_ack
|= NPCM_PECI_CTRL_ABRT_ERR
;
164 * All commands should be ended up with a NPCM_PECI_CTRL_DONE
165 * bit set even in an error case.
167 if (status
& NPCM_PECI_CTRL_DONE
) {
168 status_ack
|= NPCM_PECI_CTRL_DONE
;
169 complete(&priv
->xfer_complete
);
172 regmap_write_bits(priv
->regmap
, NPCM_PECI_CTL_STS
, NPCM_PECI_INT_MASK
, status_ack
);
174 spin_unlock(&priv
->lock
);
178 static int npcm_peci_init_ctrl(struct npcm_peci
*priv
)
183 priv
->clk
= devm_clk_get_enabled(priv
->dev
, NULL
);
184 if (IS_ERR(priv
->clk
)) {
185 dev_err(priv
->dev
, "failed to get ref clock\n");
186 return PTR_ERR(priv
->clk
);
189 ret
= device_property_read_u32(priv
->dev
, "cmd-timeout-ms", &priv
->cmd_timeout_ms
);
191 priv
->cmd_timeout_ms
= NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT
;
192 } else if (priv
->cmd_timeout_ms
> NPCM_PECI_CMD_TIMEOUT_MS_MAX
||
193 priv
->cmd_timeout_ms
== 0) {
194 dev_warn(priv
->dev
, "invalid cmd-timeout-ms: %u, falling back to: %u\n",
195 priv
->cmd_timeout_ms
, NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT
);
197 priv
->cmd_timeout_ms
= NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT
;
200 regmap_update_bits(priv
->regmap
, NPCM_PECI_CTL2
, NPCM_PECI_CTL2_MASK
,
201 NPCM_PECI_PULL_DOWN_DEFAULT
<< 6);
203 regmap_update_bits(priv
->regmap
, NPCM_PECI_PDDR
, NPCM_PECI_PDDR_MASK
,
204 NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT
);
206 ret
= regmap_read_poll_timeout(priv
->regmap
, NPCM_PECI_CTL_STS
, cmd_sts
,
207 !(cmd_sts
& NPCM_PECI_CTRL_START_BUSY
),
208 NPCM_PECI_IDLE_CHECK_INTERVAL_USEC
,
209 NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC
);
211 return ret
; /* -ETIMEDOUT */
213 /* PECI interrupt enable */
214 regmap_update_bits(priv
->regmap
, NPCM_PECI_CTL_STS
, NPCM_PECI_CTRL_DONE_INT_EN
,
215 NPCM_PECI_CTRL_DONE_INT_EN
);
220 static const struct regmap_config npcm_peci_regmap_config
= {
223 .max_register
= NPCM_PECI_MAX_REG
,
227 static const struct peci_controller_ops npcm_ops
= {
228 .xfer
= npcm_peci_xfer
,
231 static int npcm_peci_probe(struct platform_device
*pdev
)
233 struct peci_controller
*controller
;
234 struct npcm_peci
*priv
;
238 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
242 priv
->dev
= &pdev
->dev
;
243 dev_set_drvdata(&pdev
->dev
, priv
);
245 base
= devm_platform_ioremap_resource(pdev
, 0);
247 return PTR_ERR(base
);
249 priv
->regmap
= devm_regmap_init_mmio(&pdev
->dev
, base
, &npcm_peci_regmap_config
);
250 if (IS_ERR(priv
->regmap
))
251 return PTR_ERR(priv
->regmap
);
253 priv
->irq
= platform_get_irq(pdev
, 0);
257 ret
= devm_request_irq(&pdev
->dev
, priv
->irq
, npcm_peci_irq_handler
,
258 0, "peci-npcm-irq", priv
);
262 init_completion(&priv
->xfer_complete
);
263 spin_lock_init(&priv
->lock
);
265 ret
= npcm_peci_init_ctrl(priv
);
269 controller
= devm_peci_controller_add(priv
->dev
, &npcm_ops
);
270 if (IS_ERR(controller
))
271 return dev_err_probe(priv
->dev
, PTR_ERR(controller
),
272 "failed to add npcm peci controller\n");
274 priv
->controller
= controller
;
279 static const struct of_device_id npcm_peci_of_table
[] = {
280 { .compatible
= "nuvoton,npcm750-peci", },
281 { .compatible
= "nuvoton,npcm845-peci", },
284 MODULE_DEVICE_TABLE(of
, npcm_peci_of_table
);
286 static struct platform_driver npcm_peci_driver
= {
287 .probe
= npcm_peci_probe
,
289 .name
= KBUILD_MODNAME
,
290 .of_match_table
= npcm_peci_of_table
,
293 module_platform_driver(npcm_peci_driver
);
295 MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
296 MODULE_DESCRIPTION("NPCM PECI driver");
297 MODULE_LICENSE("GPL");
298 MODULE_IMPORT_NS("PECI");