]>
Commit | Line | Data |
---|---|---|
adf38bb0 ZY |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved. | |
4 | * Author: Zhichang Yuan <yuanzhichang@hisilicon.com> | |
5 | * Author: Zou Rongrong <zourongrong@huawei.com> | |
6 | * Author: John Garry <john.garry@huawei.com> | |
7 | */ | |
8 | ||
9 | #include <linux/acpi.h> | |
10 | #include <linux/console.h> | |
11 | #include <linux/delay.h> | |
12 | #include <linux/io.h> | |
13 | #include <linux/logic_pio.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/of.h> | |
16 | #include <linux/of_address.h> | |
17 | #include <linux/of_platform.h> | |
18 | #include <linux/pci.h> | |
19 | #include <linux/slab.h> | |
20 | ||
21 | #define DRV_NAME "hisi-lpc" | |
22 | ||
23 | /* | |
24 | * Setting this bit means each IO operation will target a different port | |
25 | * address; 0 means repeated IO operations will use the same port, | |
26 | * such as BT. | |
27 | */ | |
28 | #define FG_INCRADDR_LPC 0x02 | |
29 | ||
30 | struct lpc_cycle_para { | |
31 | unsigned int opflags; | |
32 | unsigned int csize; /* data length of each operation */ | |
33 | }; | |
34 | ||
35 | struct hisi_lpc_dev { | |
36 | spinlock_t cycle_lock; | |
37 | void __iomem *membase; | |
38 | struct logic_pio_hwaddr *io_host; | |
39 | }; | |
40 | ||
41 | /* The max IO cycle counts supported is four per operation at maximum */ | |
42 | #define LPC_MAX_DWIDTH 4 | |
43 | ||
44 | #define LPC_REG_STARTUP_SIGNAL 0x00 | |
45 | #define LPC_REG_STARTUP_SIGNAL_START BIT(0) | |
46 | #define LPC_REG_OP_STATUS 0x04 | |
47 | #define LPC_REG_OP_STATUS_IDLE BIT(0) | |
48 | #define LPC_REG_OP_STATUS_FINISHED BIT(1) | |
49 | #define LPC_REG_OP_LEN 0x10 /* LPC cycles count per start */ | |
50 | #define LPC_REG_CMD 0x14 | |
51 | #define LPC_REG_CMD_OP BIT(0) /* 0: read, 1: write */ | |
52 | #define LPC_REG_CMD_SAMEADDR BIT(3) | |
53 | #define LPC_REG_ADDR 0x20 /* target address */ | |
54 | #define LPC_REG_WDATA 0x24 /* write FIFO */ | |
55 | #define LPC_REG_RDATA 0x28 /* read FIFO */ | |
56 | ||
57 | /* The minimal nanosecond interval for each query on LPC cycle status */ | |
58 | #define LPC_NSEC_PERWAIT 100 | |
59 | ||
60 | /* | |
61 | * The maximum waiting time is about 128us. It is specific for stream I/O, | |
62 | * such as ins. | |
63 | * | |
64 | * The fastest IO cycle time is about 390ns, but the worst case will wait | |
65 | * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum burst | |
66 | * cycles is 16. So, the maximum waiting time is about 128us under worst | |
67 | * case. | |
68 | * | |
69 | * Choose 1300 as the maximum. | |
70 | */ | |
71 | #define LPC_MAX_WAITCNT 1300 | |
72 | ||
73 | /* About 10us. This is specific for single IO operations, such as inb */ | |
74 | #define LPC_PEROP_WAITCNT 100 | |
75 | ||
76 | static int wait_lpc_idle(unsigned char *mbase, unsigned int waitcnt) | |
77 | { | |
78 | u32 status; | |
79 | ||
80 | do { | |
81 | status = readl(mbase + LPC_REG_OP_STATUS); | |
82 | if (status & LPC_REG_OP_STATUS_IDLE) | |
83 | return (status & LPC_REG_OP_STATUS_FINISHED) ? 0 : -EIO; | |
84 | ndelay(LPC_NSEC_PERWAIT); | |
85 | } while (--waitcnt); | |
86 | ||
87 | return -ETIME; | |
88 | } | |
89 | ||
90 | /* | |
91 | * hisi_lpc_target_in - trigger a series of LPC cycles for read operation | |
92 | * @lpcdev: pointer to hisi lpc device | |
93 | * @para: some parameters used to control the lpc I/O operations | |
94 | * @addr: the lpc I/O target port address | |
95 | * @buf: where the read back data is stored | |
96 | * @opcnt: how many I/O operations required, i.e. data width | |
97 | * | |
98 | * Returns 0 on success, non-zero on fail. | |
99 | */ | |
100 | static int hisi_lpc_target_in(struct hisi_lpc_dev *lpcdev, | |
101 | struct lpc_cycle_para *para, unsigned long addr, | |
102 | unsigned char *buf, unsigned long opcnt) | |
103 | { | |
104 | unsigned int cmd_word; | |
105 | unsigned int waitcnt; | |
106 | unsigned long flags; | |
107 | int ret; | |
108 | ||
109 | if (!buf || !opcnt || !para || !para->csize || !lpcdev) | |
110 | return -EINVAL; | |
111 | ||
112 | cmd_word = 0; /* IO mode, Read */ | |
113 | waitcnt = LPC_PEROP_WAITCNT; | |
114 | if (!(para->opflags & FG_INCRADDR_LPC)) { | |
115 | cmd_word |= LPC_REG_CMD_SAMEADDR; | |
116 | waitcnt = LPC_MAX_WAITCNT; | |
117 | } | |
118 | ||
119 | /* whole operation must be atomic */ | |
120 | spin_lock_irqsave(&lpcdev->cycle_lock, flags); | |
121 | ||
122 | writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN); | |
123 | writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); | |
124 | writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR); | |
125 | ||
126 | writel(LPC_REG_STARTUP_SIGNAL_START, | |
127 | lpcdev->membase + LPC_REG_STARTUP_SIGNAL); | |
128 | ||
129 | /* whether the operation is finished */ | |
130 | ret = wait_lpc_idle(lpcdev->membase, waitcnt); | |
131 | if (ret) { | |
132 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | |
133 | return ret; | |
134 | } | |
135 | ||
136 | readsb(lpcdev->membase + LPC_REG_RDATA, buf, opcnt); | |
137 | ||
138 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | |
139 | ||
140 | return 0; | |
141 | } | |
142 | ||
143 | /* | |
144 | * hisi_lpc_target_out - trigger a series of LPC cycles for write operation | |
145 | * @lpcdev: pointer to hisi lpc device | |
146 | * @para: some parameters used to control the lpc I/O operations | |
147 | * @addr: the lpc I/O target port address | |
148 | * @buf: where the data to be written is stored | |
149 | * @opcnt: how many I/O operations required, i.e. data width | |
150 | * | |
151 | * Returns 0 on success, non-zero on fail. | |
152 | */ | |
153 | static int hisi_lpc_target_out(struct hisi_lpc_dev *lpcdev, | |
154 | struct lpc_cycle_para *para, unsigned long addr, | |
155 | const unsigned char *buf, unsigned long opcnt) | |
156 | { | |
157 | unsigned int waitcnt; | |
158 | unsigned long flags; | |
159 | u32 cmd_word; | |
160 | int ret; | |
161 | ||
162 | if (!buf || !opcnt || !para || !lpcdev) | |
163 | return -EINVAL; | |
164 | ||
165 | /* default is increasing address */ | |
166 | cmd_word = LPC_REG_CMD_OP; /* IO mode, write */ | |
167 | waitcnt = LPC_PEROP_WAITCNT; | |
168 | if (!(para->opflags & FG_INCRADDR_LPC)) { | |
169 | cmd_word |= LPC_REG_CMD_SAMEADDR; | |
170 | waitcnt = LPC_MAX_WAITCNT; | |
171 | } | |
172 | ||
173 | spin_lock_irqsave(&lpcdev->cycle_lock, flags); | |
174 | ||
175 | writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN); | |
176 | writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); | |
177 | writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR); | |
178 | ||
179 | writesb(lpcdev->membase + LPC_REG_WDATA, buf, opcnt); | |
180 | ||
181 | writel(LPC_REG_STARTUP_SIGNAL_START, | |
182 | lpcdev->membase + LPC_REG_STARTUP_SIGNAL); | |
183 | ||
184 | /* whether the operation is finished */ | |
185 | ret = wait_lpc_idle(lpcdev->membase, waitcnt); | |
186 | ||
187 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | |
188 | ||
189 | return ret; | |
190 | } | |
191 | ||
192 | static unsigned long hisi_lpc_pio_to_addr(struct hisi_lpc_dev *lpcdev, | |
193 | unsigned long pio) | |
194 | { | |
195 | return pio - lpcdev->io_host->io_start + lpcdev->io_host->hw_start; | |
196 | } | |
197 | ||
198 | /* | |
199 | * hisi_lpc_comm_in - input the data in a single operation | |
200 | * @hostdata: pointer to the device information relevant to LPC controller | |
201 | * @pio: the target I/O port address | |
202 | * @dwidth: the data length required to read from the target I/O port | |
203 | * | |
204 | * When success, data is returned. Otherwise, ~0 is returned. | |
205 | */ | |
206 | static u32 hisi_lpc_comm_in(void *hostdata, unsigned long pio, size_t dwidth) | |
207 | { | |
208 | struct hisi_lpc_dev *lpcdev = hostdata; | |
209 | struct lpc_cycle_para iopara; | |
210 | unsigned long addr; | |
211 | u32 rd_data = 0; | |
212 | int ret; | |
213 | ||
214 | if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH) | |
215 | return ~0; | |
216 | ||
217 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | |
218 | ||
219 | iopara.opflags = FG_INCRADDR_LPC; | |
220 | iopara.csize = dwidth; | |
221 | ||
222 | ret = hisi_lpc_target_in(lpcdev, &iopara, addr, | |
223 | (unsigned char *)&rd_data, dwidth); | |
224 | if (ret) | |
225 | return ~0; | |
226 | ||
227 | return le32_to_cpu(rd_data); | |
228 | } | |
229 | ||
230 | /* | |
231 | * hisi_lpc_comm_out - output the data in a single operation | |
232 | * @hostdata: pointer to the device information relevant to LPC controller | |
233 | * @pio: the target I/O port address | |
234 | * @val: a value to be output from caller, maximum is four bytes | |
235 | * @dwidth: the data width required writing to the target I/O port | |
236 | * | |
237 | * This function corresponds to out(b,w,l) only. | |
238 | */ | |
239 | static void hisi_lpc_comm_out(void *hostdata, unsigned long pio, | |
240 | u32 val, size_t dwidth) | |
241 | { | |
242 | struct hisi_lpc_dev *lpcdev = hostdata; | |
243 | struct lpc_cycle_para iopara; | |
244 | const unsigned char *buf; | |
245 | unsigned long addr; | |
246 | ||
247 | if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH) | |
248 | return; | |
249 | ||
250 | val = cpu_to_le32(val); | |
251 | ||
252 | buf = (const unsigned char *)&val; | |
253 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | |
254 | ||
255 | iopara.opflags = FG_INCRADDR_LPC; | |
256 | iopara.csize = dwidth; | |
257 | ||
258 | hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth); | |
259 | } | |
260 | ||
261 | /* | |
262 | * hisi_lpc_comm_ins - input the data in the buffer in multiple operations | |
263 | * @hostdata: pointer to the device information relevant to LPC controller | |
264 | * @pio: the target I/O port address | |
265 | * @buffer: a buffer where read/input data bytes are stored | |
266 | * @dwidth: the data width required writing to the target I/O port | |
267 | * @count: how many data units whose length is dwidth will be read | |
268 | * | |
269 | * When success, the data read back is stored in buffer pointed by buffer. | |
270 | * Returns 0 on success, -errno otherwise. | |
271 | */ | |
272 | static u32 hisi_lpc_comm_ins(void *hostdata, unsigned long pio, void *buffer, | |
273 | size_t dwidth, unsigned int count) | |
274 | { | |
275 | struct hisi_lpc_dev *lpcdev = hostdata; | |
276 | unsigned char *buf = buffer; | |
277 | struct lpc_cycle_para iopara; | |
278 | unsigned long addr; | |
279 | ||
280 | if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH) | |
281 | return -EINVAL; | |
282 | ||
283 | iopara.opflags = 0; | |
284 | if (dwidth > 1) | |
285 | iopara.opflags |= FG_INCRADDR_LPC; | |
286 | iopara.csize = dwidth; | |
287 | ||
288 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | |
289 | ||
290 | do { | |
291 | int ret; | |
292 | ||
293 | ret = hisi_lpc_target_in(lpcdev, &iopara, addr, buf, dwidth); | |
294 | if (ret) | |
295 | return ret; | |
296 | buf += dwidth; | |
297 | } while (--count); | |
298 | ||
299 | return 0; | |
300 | } | |
301 | ||
302 | /* | |
303 | * hisi_lpc_comm_outs - output the data in the buffer in multiple operations | |
304 | * @hostdata: pointer to the device information relevant to LPC controller | |
305 | * @pio: the target I/O port address | |
306 | * @buffer: a buffer where write/output data bytes are stored | |
307 | * @dwidth: the data width required writing to the target I/O port | |
308 | * @count: how many data units whose length is dwidth will be written | |
309 | */ | |
310 | static void hisi_lpc_comm_outs(void *hostdata, unsigned long pio, | |
311 | const void *buffer, size_t dwidth, | |
312 | unsigned int count) | |
313 | { | |
314 | struct hisi_lpc_dev *lpcdev = hostdata; | |
315 | struct lpc_cycle_para iopara; | |
316 | const unsigned char *buf = buffer; | |
317 | unsigned long addr; | |
318 | ||
319 | if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH) | |
320 | return; | |
321 | ||
322 | iopara.opflags = 0; | |
323 | if (dwidth > 1) | |
324 | iopara.opflags |= FG_INCRADDR_LPC; | |
325 | iopara.csize = dwidth; | |
326 | ||
327 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | |
328 | do { | |
329 | if (hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth)) | |
330 | break; | |
331 | buf += dwidth; | |
332 | } while (--count); | |
333 | } | |
334 | ||
335 | static const struct logic_pio_host_ops hisi_lpc_ops = { | |
336 | .in = hisi_lpc_comm_in, | |
337 | .out = hisi_lpc_comm_out, | |
338 | .ins = hisi_lpc_comm_ins, | |
339 | .outs = hisi_lpc_comm_outs, | |
340 | }; | |
341 | ||
342 | /* | |
343 | * hisi_lpc_probe - the probe callback function for hisi lpc host, | |
344 | * will finish all the initialization. | |
345 | * @pdev: the platform device corresponding to hisi lpc host | |
346 | * | |
347 | * Returns 0 on success, non-zero on fail. | |
348 | */ | |
349 | static int hisi_lpc_probe(struct platform_device *pdev) | |
350 | { | |
351 | struct device *dev = &pdev->dev; | |
352 | struct acpi_device *acpi_device = ACPI_COMPANION(dev); | |
353 | struct logic_pio_hwaddr *range; | |
354 | struct hisi_lpc_dev *lpcdev; | |
355 | resource_size_t io_end; | |
356 | struct resource *res; | |
357 | int ret; | |
358 | ||
359 | lpcdev = devm_kzalloc(dev, sizeof(*lpcdev), GFP_KERNEL); | |
360 | if (!lpcdev) | |
361 | return -ENOMEM; | |
362 | ||
363 | spin_lock_init(&lpcdev->cycle_lock); | |
364 | ||
365 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
366 | lpcdev->membase = devm_ioremap_resource(dev, res); | |
367 | if (IS_ERR(lpcdev->membase)) | |
368 | return PTR_ERR(lpcdev->membase); | |
369 | ||
370 | range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL); | |
371 | if (!range) | |
372 | return -ENOMEM; | |
373 | ||
374 | range->fwnode = dev->fwnode; | |
375 | range->flags = LOGIC_PIO_INDIRECT; | |
376 | range->size = PIO_INDIRECT_SIZE; | |
377 | ||
378 | ret = logic_pio_register_range(range); | |
379 | if (ret) { | |
380 | dev_err(dev, "register IO range failed (%d)!\n", ret); | |
381 | return ret; | |
382 | } | |
383 | lpcdev->io_host = range; | |
384 | ||
385 | /* register the LPC host PIO resources */ | |
386 | if (!acpi_device) { | |
387 | ret = of_platform_populate(dev->of_node, NULL, NULL, dev); | |
388 | if (ret) | |
389 | return ret; | |
390 | } | |
391 | ||
392 | lpcdev->io_host->hostdata = lpcdev; | |
393 | lpcdev->io_host->ops = &hisi_lpc_ops; | |
394 | ||
395 | io_end = lpcdev->io_host->io_start + lpcdev->io_host->size; | |
396 | dev_info(dev, "registered range [%pa - %pa]\n", | |
397 | &lpcdev->io_host->io_start, &io_end); | |
398 | ||
399 | return ret; | |
400 | } | |
401 | ||
402 | static const struct of_device_id hisi_lpc_of_match[] = { | |
403 | { .compatible = "hisilicon,hip06-lpc", }, | |
404 | { .compatible = "hisilicon,hip07-lpc", }, | |
405 | {} | |
406 | }; | |
407 | ||
408 | static struct platform_driver hisi_lpc_driver = { | |
409 | .driver = { | |
410 | .name = DRV_NAME, | |
411 | .of_match_table = hisi_lpc_of_match, | |
412 | }, | |
413 | .probe = hisi_lpc_probe, | |
414 | }; | |
415 | builtin_platform_driver(hisi_lpc_driver); |