aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhichang Yuan <yuanzhichang@hisilicon.com>2018-03-21 18:23:02 -0400
committerBjorn Helgaas <helgaas@kernel.org>2018-04-04 09:42:48 -0400
commitadf38bb0b5956ab5469acb1ca981a9287c7ad1d8 (patch)
treec08d2e7f88c69883ae7aff65647e0c9d9589e928
parent65af618d2c559f8eb19d80d03a23029651a59de4 (diff)
HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings
The low-pin-count (LPC) interface of Hip06/Hip07 accesses I/O port space of peripherals. Implement the LPC host controller driver which performs the I/O operations on the underlying hardware. We don't want to touch existing drivers such as ipmi-bt, so this driver applies the indirect-IO introduced in the previous patch after registering an indirect-IO node to the indirect-IO devices list which will be searched by the I/O accessors to retrieve the host-local I/O port. The driver config is set as a bool instead of a tristate. The reason here is that, by the very nature of the driver providing a logical PIO range, it does not make sense to have this driver as a loadable module. Another more specific reason is that the Huawei D03 board which includes Hip06 SoC requires the LPC bus for UART console, so should be built in. Tested-by: dann frazier <dann.frazier@canonical.com> Signed-off-by: Zou Rongrong <zourongrong@huawei.com> Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com> Signed-off-by: John Garry <john.garry@huawei.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Acked-by: Rob Herring <robh@kernel.org> # dts part
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt33
-rw-r--r--drivers/bus/Kconfig8
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/hisi_lpc.c415
4 files changed, 457 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
new file mode 100644
index 000000000000..10bd35f9207f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
@@ -0,0 +1,33 @@
1Hisilicon Hip06 Low Pin Count device
2 Hisilicon Hip06 SoCs implement a Low Pin Count (LPC) controller, which
3 provides I/O access to some legacy ISA devices.
4 Hip06 is based on arm64 architecture where there is no I/O space. So, the
5 I/O ports here are not CPU addresses, and there is no 'ranges' property in
6 LPC device node.
7
8Required properties:
9- compatible: value should be as follows:
10 (a) "hisilicon,hip06-lpc"
11 (b) "hisilicon,hip07-lpc"
12- #address-cells: must be 2 which stick to the ISA/EISA binding doc.
13- #size-cells: must be 1 which stick to the ISA/EISA binding doc.
14- reg: base memory range where the LPC register set is mapped.
15
16Note:
17 The node name before '@' must be "isa" to represent the binding stick to the
18 ISA/EISA binding specification.
19
20Example:
21
22isa@a01b0000 {
23 compatible = "hisilicon,hip06-lpc";
24 #address-cells = <2>;
25 #size-cells = <1>;
26 reg = <0x0 0xa01b0000 0x0 0x1000>;
27
28 ipmi0: bt@e4 {
29 compatible = "ipmi-bt";
30 device_type = "ipmi";
31 reg = <0x01 0xe4 0x04>;
32 };
33};
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 57e011d36a79..a3fad0f0292f 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -65,6 +65,14 @@ config BRCMSTB_GISB_ARB
65 arbiter. This driver provides timeout and target abort error handling 65 arbiter. This driver provides timeout and target abort error handling
66 and internal bus master decoding. 66 and internal bus master decoding.
67 67
68config HISILICON_LPC
69 bool "Support for ISA I/O space on HiSilicon Hip06/7"
70 depends on ARM64 && (ARCH_HISI || COMPILE_TEST)
71 select INDIRECT_PIO
72 help
73 Driver to enable I/O access to devices attached to the Low Pin
74 Count bus on the HiSilicon Hip06/7 SoC.
75
68config IMX_WEIM 76config IMX_WEIM
69 bool "Freescale EIM DRIVER" 77 bool "Freescale EIM DRIVER"
70 depends on ARCH_MXC 78 depends on ARCH_MXC
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 9bcd0bf3954b..50bb12a971a0 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -7,6 +7,7 @@
7obj-$(CONFIG_ARM_CCI) += arm-cci.o 7obj-$(CONFIG_ARM_CCI) += arm-cci.o
8obj-$(CONFIG_ARM_CCN) += arm-ccn.o 8obj-$(CONFIG_ARM_CCN) += arm-ccn.o
9 9
10obj-$(CONFIG_HISILICON_LPC) += hisi_lpc.o
10obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o 11obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o
11obj-$(CONFIG_IMX_WEIM) += imx-weim.o 12obj-$(CONFIG_IMX_WEIM) += imx-weim.o
12obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o 13obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
new file mode 100644
index 000000000000..6123bff3215f
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,415 @@
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
30struct lpc_cycle_para {
31 unsigned int opflags;
32 unsigned int csize; /* data length of each operation */
33};
34
35struct 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
76static 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 */
100static 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 */
153static 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
192static 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 */
206static 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 */
239static 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 */
272static 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 */
310static 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
335static 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 */
349static 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
402static const struct of_device_id hisi_lpc_of_match[] = {
403 { .compatible = "hisilicon,hip06-lpc", },
404 { .compatible = "hisilicon,hip07-lpc", },
405 {}
406};
407
408static 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};
415builtin_platform_driver(hisi_lpc_driver);