| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 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/serial_8250.h> | 
|  | 20 | #include <linux/slab.h> | 
|  | 21 |  | 
|  | 22 | #define DRV_NAME "hisi-lpc" | 
|  | 23 |  | 
|  | 24 | /* | 
|  | 25 | * Setting this bit means each IO operation will target a different port | 
|  | 26 | * address; 0 means repeated IO operations will use the same port, | 
|  | 27 | * such as BT. | 
|  | 28 | */ | 
|  | 29 | #define FG_INCRADDR_LPC		0x02 | 
|  | 30 |  | 
|  | 31 | struct lpc_cycle_para { | 
|  | 32 | unsigned int opflags; | 
|  | 33 | unsigned int csize; /* data length of each operation */ | 
|  | 34 | }; | 
|  | 35 |  | 
|  | 36 | struct hisi_lpc_dev { | 
|  | 37 | spinlock_t cycle_lock; | 
|  | 38 | void __iomem  *membase; | 
|  | 39 | struct logic_pio_hwaddr *io_host; | 
|  | 40 | }; | 
|  | 41 |  | 
|  | 42 | /* The max IO cycle counts supported is four per operation at maximum */ | 
|  | 43 | #define LPC_MAX_DWIDTH	4 | 
|  | 44 |  | 
|  | 45 | #define LPC_REG_STARTUP_SIGNAL		0x00 | 
|  | 46 | #define LPC_REG_STARTUP_SIGNAL_START	BIT(0) | 
|  | 47 | #define LPC_REG_OP_STATUS		0x04 | 
|  | 48 | #define LPC_REG_OP_STATUS_IDLE		BIT(0) | 
|  | 49 | #define LPC_REG_OP_STATUS_FINISHED	BIT(1) | 
|  | 50 | #define LPC_REG_OP_LEN			0x10 /* LPC cycles count per start */ | 
|  | 51 | #define LPC_REG_CMD			0x14 | 
|  | 52 | #define LPC_REG_CMD_OP			BIT(0) /* 0: read, 1: write */ | 
|  | 53 | #define LPC_REG_CMD_SAMEADDR		BIT(3) | 
|  | 54 | #define LPC_REG_ADDR			0x20 /* target address */ | 
|  | 55 | #define LPC_REG_WDATA			0x24 /* write FIFO */ | 
|  | 56 | #define LPC_REG_RDATA			0x28 /* read FIFO */ | 
|  | 57 |  | 
|  | 58 | /* The minimal nanosecond interval for each query on LPC cycle status */ | 
|  | 59 | #define LPC_NSEC_PERWAIT	100 | 
|  | 60 |  | 
|  | 61 | /* | 
|  | 62 | * The maximum waiting time is about 128us.  It is specific for stream I/O, | 
|  | 63 | * such as ins. | 
|  | 64 | * | 
|  | 65 | * The fastest IO cycle time is about 390ns, but the worst case will wait | 
|  | 66 | * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum burst | 
|  | 67 | * cycles is 16. So, the maximum waiting time is about 128us under worst | 
|  | 68 | * case. | 
|  | 69 | * | 
|  | 70 | * Choose 1300 as the maximum. | 
|  | 71 | */ | 
|  | 72 | #define LPC_MAX_WAITCNT		1300 | 
|  | 73 |  | 
|  | 74 | /* About 10us. This is specific for single IO operations, such as inb */ | 
|  | 75 | #define LPC_PEROP_WAITCNT	100 | 
|  | 76 |  | 
|  | 77 | static int wait_lpc_idle(unsigned char *mbase, unsigned int waitcnt) | 
|  | 78 | { | 
|  | 79 | u32 status; | 
|  | 80 |  | 
|  | 81 | do { | 
|  | 82 | status = readl(mbase + LPC_REG_OP_STATUS); | 
|  | 83 | if (status & LPC_REG_OP_STATUS_IDLE) | 
|  | 84 | return (status & LPC_REG_OP_STATUS_FINISHED) ? 0 : -EIO; | 
|  | 85 | ndelay(LPC_NSEC_PERWAIT); | 
|  | 86 | } while (--waitcnt); | 
|  | 87 |  | 
|  | 88 | return -ETIME; | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | /* | 
|  | 92 | * hisi_lpc_target_in - trigger a series of LPC cycles for read operation | 
|  | 93 | * @lpcdev: pointer to hisi lpc device | 
|  | 94 | * @para: some parameters used to control the lpc I/O operations | 
|  | 95 | * @addr: the lpc I/O target port address | 
|  | 96 | * @buf: where the read back data is stored | 
|  | 97 | * @opcnt: how many I/O operations required, i.e. data width | 
|  | 98 | * | 
|  | 99 | * Returns 0 on success, non-zero on fail. | 
|  | 100 | */ | 
|  | 101 | static int hisi_lpc_target_in(struct hisi_lpc_dev *lpcdev, | 
|  | 102 | struct lpc_cycle_para *para, unsigned long addr, | 
|  | 103 | unsigned char *buf, unsigned long opcnt) | 
|  | 104 | { | 
|  | 105 | unsigned int cmd_word; | 
|  | 106 | unsigned int waitcnt; | 
|  | 107 | unsigned long flags; | 
|  | 108 | int ret; | 
|  | 109 |  | 
|  | 110 | if (!buf || !opcnt || !para || !para->csize || !lpcdev) | 
|  | 111 | return -EINVAL; | 
|  | 112 |  | 
|  | 113 | cmd_word = 0; /* IO mode, Read */ | 
|  | 114 | waitcnt = LPC_PEROP_WAITCNT; | 
|  | 115 | if (!(para->opflags & FG_INCRADDR_LPC)) { | 
|  | 116 | cmd_word |= LPC_REG_CMD_SAMEADDR; | 
|  | 117 | waitcnt = LPC_MAX_WAITCNT; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | /* whole operation must be atomic */ | 
|  | 121 | spin_lock_irqsave(&lpcdev->cycle_lock, flags); | 
|  | 122 |  | 
|  | 123 | writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN); | 
|  | 124 | writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); | 
|  | 125 | writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR); | 
|  | 126 |  | 
|  | 127 | writel(LPC_REG_STARTUP_SIGNAL_START, | 
|  | 128 | lpcdev->membase + LPC_REG_STARTUP_SIGNAL); | 
|  | 129 |  | 
|  | 130 | /* whether the operation is finished */ | 
|  | 131 | ret = wait_lpc_idle(lpcdev->membase, waitcnt); | 
|  | 132 | if (ret) { | 
|  | 133 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | 
|  | 134 | return ret; | 
|  | 135 | } | 
|  | 136 |  | 
|  | 137 | readsb(lpcdev->membase + LPC_REG_RDATA, buf, opcnt); | 
|  | 138 |  | 
|  | 139 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | 
|  | 140 |  | 
|  | 141 | return 0; | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | /* | 
|  | 145 | * hisi_lpc_target_out - trigger a series of LPC cycles for write operation | 
|  | 146 | * @lpcdev: pointer to hisi lpc device | 
|  | 147 | * @para: some parameters used to control the lpc I/O operations | 
|  | 148 | * @addr: the lpc I/O target port address | 
|  | 149 | * @buf: where the data to be written is stored | 
|  | 150 | * @opcnt: how many I/O operations required, i.e. data width | 
|  | 151 | * | 
|  | 152 | * Returns 0 on success, non-zero on fail. | 
|  | 153 | */ | 
|  | 154 | static int hisi_lpc_target_out(struct hisi_lpc_dev *lpcdev, | 
|  | 155 | struct lpc_cycle_para *para, unsigned long addr, | 
|  | 156 | const unsigned char *buf, unsigned long opcnt) | 
|  | 157 | { | 
|  | 158 | unsigned int waitcnt; | 
|  | 159 | unsigned long flags; | 
|  | 160 | u32 cmd_word; | 
|  | 161 | int ret; | 
|  | 162 |  | 
|  | 163 | if (!buf || !opcnt || !para || !lpcdev) | 
|  | 164 | return -EINVAL; | 
|  | 165 |  | 
|  | 166 | /* default is increasing address */ | 
|  | 167 | cmd_word = LPC_REG_CMD_OP; /* IO mode, write */ | 
|  | 168 | waitcnt = LPC_PEROP_WAITCNT; | 
|  | 169 | if (!(para->opflags & FG_INCRADDR_LPC)) { | 
|  | 170 | cmd_word |= LPC_REG_CMD_SAMEADDR; | 
|  | 171 | waitcnt = LPC_MAX_WAITCNT; | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | spin_lock_irqsave(&lpcdev->cycle_lock, flags); | 
|  | 175 |  | 
|  | 176 | writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN); | 
|  | 177 | writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); | 
|  | 178 | writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR); | 
|  | 179 |  | 
|  | 180 | writesb(lpcdev->membase + LPC_REG_WDATA, buf, opcnt); | 
|  | 181 |  | 
|  | 182 | writel(LPC_REG_STARTUP_SIGNAL_START, | 
|  | 183 | lpcdev->membase + LPC_REG_STARTUP_SIGNAL); | 
|  | 184 |  | 
|  | 185 | /* whether the operation is finished */ | 
|  | 186 | ret = wait_lpc_idle(lpcdev->membase, waitcnt); | 
|  | 187 |  | 
|  | 188 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | 
|  | 189 |  | 
|  | 190 | return ret; | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | static unsigned long hisi_lpc_pio_to_addr(struct hisi_lpc_dev *lpcdev, | 
|  | 194 | unsigned long pio) | 
|  | 195 | { | 
|  | 196 | return pio - lpcdev->io_host->io_start + lpcdev->io_host->hw_start; | 
|  | 197 | } | 
|  | 198 |  | 
|  | 199 | /* | 
|  | 200 | * hisi_lpc_comm_in - input the data in a single operation | 
|  | 201 | * @hostdata: pointer to the device information relevant to LPC controller | 
|  | 202 | * @pio: the target I/O port address | 
|  | 203 | * @dwidth: the data length required to read from the target I/O port | 
|  | 204 | * | 
|  | 205 | * When success, data is returned. Otherwise, ~0 is returned. | 
|  | 206 | */ | 
|  | 207 | static u32 hisi_lpc_comm_in(void *hostdata, unsigned long pio, size_t dwidth) | 
|  | 208 | { | 
|  | 209 | struct hisi_lpc_dev *lpcdev = hostdata; | 
|  | 210 | struct lpc_cycle_para iopara; | 
|  | 211 | unsigned long addr; | 
|  | 212 | u32 rd_data = 0; | 
|  | 213 | int ret; | 
|  | 214 |  | 
|  | 215 | if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH) | 
|  | 216 | return ~0; | 
|  | 217 |  | 
|  | 218 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | 
|  | 219 |  | 
|  | 220 | iopara.opflags = FG_INCRADDR_LPC; | 
|  | 221 | iopara.csize = dwidth; | 
|  | 222 |  | 
|  | 223 | ret = hisi_lpc_target_in(lpcdev, &iopara, addr, | 
|  | 224 | (unsigned char *)&rd_data, dwidth); | 
|  | 225 | if (ret) | 
|  | 226 | return ~0; | 
|  | 227 |  | 
|  | 228 | return le32_to_cpu(rd_data); | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | /* | 
|  | 232 | * hisi_lpc_comm_out - output the data in a single operation | 
|  | 233 | * @hostdata: pointer to the device information relevant to LPC controller | 
|  | 234 | * @pio: the target I/O port address | 
|  | 235 | * @val: a value to be output from caller, maximum is four bytes | 
|  | 236 | * @dwidth: the data width required writing to the target I/O port | 
|  | 237 | * | 
|  | 238 | * This function corresponds to out(b,w,l) only. | 
|  | 239 | */ | 
|  | 240 | static void hisi_lpc_comm_out(void *hostdata, unsigned long pio, | 
|  | 241 | u32 val, size_t dwidth) | 
|  | 242 | { | 
|  | 243 | struct hisi_lpc_dev *lpcdev = hostdata; | 
|  | 244 | struct lpc_cycle_para iopara; | 
|  | 245 | const unsigned char *buf; | 
|  | 246 | unsigned long addr; | 
|  | 247 |  | 
|  | 248 | if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH) | 
|  | 249 | return; | 
|  | 250 |  | 
|  | 251 | val = cpu_to_le32(val); | 
|  | 252 |  | 
|  | 253 | buf = (const unsigned char *)&val; | 
|  | 254 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | 
|  | 255 |  | 
|  | 256 | iopara.opflags = FG_INCRADDR_LPC; | 
|  | 257 | iopara.csize = dwidth; | 
|  | 258 |  | 
|  | 259 | hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth); | 
|  | 260 | } | 
|  | 261 |  | 
|  | 262 | /* | 
|  | 263 | * hisi_lpc_comm_ins - input the data in the buffer in multiple operations | 
|  | 264 | * @hostdata: pointer to the device information relevant to LPC controller | 
|  | 265 | * @pio: the target I/O port address | 
|  | 266 | * @buffer: a buffer where read/input data bytes are stored | 
|  | 267 | * @dwidth: the data width required writing to the target I/O port | 
|  | 268 | * @count: how many data units whose length is dwidth will be read | 
|  | 269 | * | 
|  | 270 | * When success, the data read back is stored in buffer pointed by buffer. | 
|  | 271 | * Returns 0 on success, -errno otherwise. | 
|  | 272 | */ | 
|  | 273 | static u32 hisi_lpc_comm_ins(void *hostdata, unsigned long pio, void *buffer, | 
|  | 274 | size_t dwidth, unsigned int count) | 
|  | 275 | { | 
|  | 276 | struct hisi_lpc_dev *lpcdev = hostdata; | 
|  | 277 | unsigned char *buf = buffer; | 
|  | 278 | struct lpc_cycle_para iopara; | 
|  | 279 | unsigned long addr; | 
|  | 280 |  | 
|  | 281 | if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH) | 
|  | 282 | return -EINVAL; | 
|  | 283 |  | 
|  | 284 | iopara.opflags = 0; | 
|  | 285 | if (dwidth > 1) | 
|  | 286 | iopara.opflags |= FG_INCRADDR_LPC; | 
|  | 287 | iopara.csize = dwidth; | 
|  | 288 |  | 
|  | 289 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | 
|  | 290 |  | 
|  | 291 | do { | 
|  | 292 | int ret; | 
|  | 293 |  | 
|  | 294 | ret = hisi_lpc_target_in(lpcdev, &iopara, addr, buf, dwidth); | 
|  | 295 | if (ret) | 
|  | 296 | return ret; | 
|  | 297 | buf += dwidth; | 
|  | 298 | } while (--count); | 
|  | 299 |  | 
|  | 300 | return 0; | 
|  | 301 | } | 
|  | 302 |  | 
|  | 303 | /* | 
|  | 304 | * hisi_lpc_comm_outs - output the data in the buffer in multiple operations | 
|  | 305 | * @hostdata: pointer to the device information relevant to LPC controller | 
|  | 306 | * @pio: the target I/O port address | 
|  | 307 | * @buffer: a buffer where write/output data bytes are stored | 
|  | 308 | * @dwidth: the data width required writing to the target I/O port | 
|  | 309 | * @count: how many data units whose length is dwidth will be written | 
|  | 310 | */ | 
|  | 311 | static void hisi_lpc_comm_outs(void *hostdata, unsigned long pio, | 
|  | 312 | const void *buffer, size_t dwidth, | 
|  | 313 | unsigned int count) | 
|  | 314 | { | 
|  | 315 | struct hisi_lpc_dev *lpcdev = hostdata; | 
|  | 316 | struct lpc_cycle_para iopara; | 
|  | 317 | const unsigned char *buf = buffer; | 
|  | 318 | unsigned long addr; | 
|  | 319 |  | 
|  | 320 | if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH) | 
|  | 321 | return; | 
|  | 322 |  | 
|  | 323 | iopara.opflags = 0; | 
|  | 324 | if (dwidth > 1) | 
|  | 325 | iopara.opflags |= FG_INCRADDR_LPC; | 
|  | 326 | iopara.csize = dwidth; | 
|  | 327 |  | 
|  | 328 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | 
|  | 329 | do { | 
|  | 330 | if (hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth)) | 
|  | 331 | break; | 
|  | 332 | buf += dwidth; | 
|  | 333 | } while (--count); | 
|  | 334 | } | 
|  | 335 |  | 
|  | 336 | static const struct logic_pio_host_ops hisi_lpc_ops = { | 
|  | 337 | .in = hisi_lpc_comm_in, | 
|  | 338 | .out = hisi_lpc_comm_out, | 
|  | 339 | .ins = hisi_lpc_comm_ins, | 
|  | 340 | .outs = hisi_lpc_comm_outs, | 
|  | 341 | }; | 
|  | 342 |  | 
|  | 343 | #ifdef CONFIG_ACPI | 
|  | 344 | static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, | 
|  | 345 | struct acpi_device *host, | 
|  | 346 | struct resource *res) | 
|  | 347 | { | 
|  | 348 | unsigned long sys_port; | 
|  | 349 | resource_size_t len = resource_size(res); | 
|  | 350 |  | 
|  | 351 | sys_port = logic_pio_trans_hwaddr(&host->fwnode, res->start, len); | 
|  | 352 | if (sys_port == ~0UL) | 
|  | 353 | return -EFAULT; | 
|  | 354 |  | 
|  | 355 | res->start = sys_port; | 
|  | 356 | res->end = sys_port + len; | 
|  | 357 |  | 
|  | 358 | return 0; | 
|  | 359 | } | 
|  | 360 |  | 
|  | 361 | /* | 
|  | 362 | * hisi_lpc_acpi_set_io_res - set the resources for a child | 
|  | 363 | * @child: the device node to be updated the I/O resource | 
|  | 364 | * @hostdev: the device node associated with host controller | 
|  | 365 | * @res: double pointer to be set to the address of translated resources | 
|  | 366 | * @num_res: pointer to variable to hold the number of translated resources | 
|  | 367 | * | 
|  | 368 | * Returns 0 when successful, and a negative value for failure. | 
|  | 369 | * | 
|  | 370 | * For a given host controller, each child device will have an associated | 
|  | 371 | * host-relative address resource.  This function will return the translated | 
|  | 372 | * logical PIO addresses for each child devices resources. | 
|  | 373 | */ | 
|  | 374 | static int hisi_lpc_acpi_set_io_res(struct device *child, | 
|  | 375 | struct device *hostdev, | 
|  | 376 | const struct resource **res, int *num_res) | 
|  | 377 | { | 
|  | 378 | struct acpi_device *adev; | 
|  | 379 | struct acpi_device *host; | 
|  | 380 | struct resource_entry *rentry; | 
|  | 381 | LIST_HEAD(resource_list); | 
|  | 382 | struct resource *resources; | 
|  | 383 | int count; | 
|  | 384 | int i; | 
|  | 385 |  | 
|  | 386 | if (!child || !hostdev) | 
|  | 387 | return -EINVAL; | 
|  | 388 |  | 
|  | 389 | host = to_acpi_device(hostdev); | 
|  | 390 | adev = to_acpi_device(child); | 
|  | 391 |  | 
|  | 392 | if (!adev->status.present) { | 
|  | 393 | dev_dbg(child, "device is not present\n"); | 
|  | 394 | return -EIO; | 
|  | 395 | } | 
|  | 396 |  | 
|  | 397 | if (acpi_device_enumerated(adev)) { | 
|  | 398 | dev_dbg(child, "has been enumerated\n"); | 
|  | 399 | return -EIO; | 
|  | 400 | } | 
|  | 401 |  | 
|  | 402 | /* | 
|  | 403 | * The following code segment to retrieve the resources is common to | 
|  | 404 | * acpi_create_platform_device(), so consider a common helper function | 
|  | 405 | * in future. | 
|  | 406 | */ | 
|  | 407 | count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); | 
|  | 408 | if (count <= 0) { | 
|  | 409 | dev_dbg(child, "failed to get resources\n"); | 
|  | 410 | return count ? count : -EIO; | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | resources = devm_kcalloc(hostdev, count, sizeof(*resources), | 
|  | 414 | GFP_KERNEL); | 
|  | 415 | if (!resources) { | 
|  | 416 | dev_warn(hostdev, "could not allocate memory for %d resources\n", | 
|  | 417 | count); | 
|  | 418 | acpi_dev_free_resource_list(&resource_list); | 
|  | 419 | return -ENOMEM; | 
|  | 420 | } | 
|  | 421 | count = 0; | 
|  | 422 | list_for_each_entry(rentry, &resource_list, node) | 
|  | 423 | resources[count++] = *rentry->res; | 
|  | 424 |  | 
|  | 425 | acpi_dev_free_resource_list(&resource_list); | 
|  | 426 |  | 
|  | 427 | /* translate the I/O resources */ | 
|  | 428 | for (i = 0; i < count; i++) { | 
|  | 429 | int ret; | 
|  | 430 |  | 
|  | 431 | if (!(resources[i].flags & IORESOURCE_IO)) | 
|  | 432 | continue; | 
|  | 433 | ret = hisi_lpc_acpi_xlat_io_res(adev, host, &resources[i]); | 
|  | 434 | if (ret) { | 
|  | 435 | dev_err(child, "translate IO range %pR failed (%d)\n", | 
|  | 436 | &resources[i], ret); | 
|  | 437 | return ret; | 
|  | 438 | } | 
|  | 439 | } | 
|  | 440 | *res = resources; | 
|  | 441 | *num_res = count; | 
|  | 442 |  | 
|  | 443 | return 0; | 
|  | 444 | } | 
|  | 445 |  | 
|  | 446 | static int hisi_lpc_acpi_remove_subdev(struct device *dev, void *unused) | 
|  | 447 | { | 
|  | 448 | platform_device_unregister(to_platform_device(dev)); | 
|  | 449 | return 0; | 
|  | 450 | } | 
|  | 451 |  | 
|  | 452 | struct hisi_lpc_acpi_cell { | 
|  | 453 | const char *hid; | 
|  | 454 | const char *name; | 
|  | 455 | void *pdata; | 
|  | 456 | size_t pdata_size; | 
|  | 457 | }; | 
|  | 458 |  | 
|  | 459 | static void hisi_lpc_acpi_remove(struct device *hostdev) | 
|  | 460 | { | 
|  | 461 | struct acpi_device *adev = ACPI_COMPANION(hostdev); | 
|  | 462 | struct acpi_device *child; | 
|  | 463 |  | 
|  | 464 | device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev); | 
|  | 465 |  | 
|  | 466 | list_for_each_entry(child, &adev->children, node) | 
|  | 467 | acpi_device_clear_enumerated(child); | 
|  | 468 | } | 
|  | 469 |  | 
|  | 470 | /* | 
|  | 471 | * hisi_lpc_acpi_probe - probe children for ACPI FW | 
|  | 472 | * @hostdev: LPC host device pointer | 
|  | 473 | * | 
|  | 474 | * Returns 0 when successful, and a negative value for failure. | 
|  | 475 | * | 
|  | 476 | * Create a platform device per child, fixing up the resources | 
|  | 477 | * from bus addresses to Logical PIO addresses. | 
|  | 478 | * | 
|  | 479 | */ | 
|  | 480 | static int hisi_lpc_acpi_probe(struct device *hostdev) | 
|  | 481 | { | 
|  | 482 | struct acpi_device *adev = ACPI_COMPANION(hostdev); | 
|  | 483 | struct acpi_device *child; | 
|  | 484 | int ret; | 
|  | 485 |  | 
|  | 486 | /* Only consider the children of the host */ | 
|  | 487 | list_for_each_entry(child, &adev->children, node) { | 
|  | 488 | const char *hid = acpi_device_hid(child); | 
|  | 489 | const struct hisi_lpc_acpi_cell *cell; | 
|  | 490 | struct platform_device *pdev; | 
|  | 491 | const struct resource *res; | 
|  | 492 | bool found = false; | 
|  | 493 | int num_res; | 
|  | 494 |  | 
|  | 495 | ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res, | 
|  | 496 | &num_res); | 
|  | 497 | if (ret) { | 
|  | 498 | dev_warn(hostdev, "set resource fail (%d)\n", ret); | 
|  | 499 | goto fail; | 
|  | 500 | } | 
|  | 501 |  | 
|  | 502 | cell = (struct hisi_lpc_acpi_cell []){ | 
|  | 503 | /* ipmi */ | 
|  | 504 | { | 
|  | 505 | .hid = "IPI0001", | 
|  | 506 | .name = "hisi-lpc-ipmi", | 
|  | 507 | }, | 
|  | 508 | /* 8250-compatible uart */ | 
|  | 509 | { | 
|  | 510 | .hid = "HISI1031", | 
|  | 511 | .name = "serial8250", | 
|  | 512 | .pdata = (struct plat_serial8250_port []) { | 
|  | 513 | { | 
|  | 514 | .iobase = res->start, | 
|  | 515 | .uartclk = 1843200, | 
|  | 516 | .iotype = UPIO_PORT, | 
|  | 517 | .flags = UPF_BOOT_AUTOCONF, | 
|  | 518 | }, | 
|  | 519 | {} | 
|  | 520 | }, | 
|  | 521 | .pdata_size = 2 * | 
|  | 522 | sizeof(struct plat_serial8250_port), | 
|  | 523 | }, | 
|  | 524 | {} | 
|  | 525 | }; | 
|  | 526 |  | 
|  | 527 | for (; cell && cell->name; cell++) { | 
|  | 528 | if (!strcmp(cell->hid, hid)) { | 
|  | 529 | found = true; | 
|  | 530 | break; | 
|  | 531 | } | 
|  | 532 | } | 
|  | 533 |  | 
|  | 534 | if (!found) { | 
|  | 535 | dev_warn(hostdev, | 
|  | 536 | "could not find cell for child device (%s)\n", | 
|  | 537 | hid); | 
|  | 538 | ret = -ENODEV; | 
|  | 539 | goto fail; | 
|  | 540 | } | 
|  | 541 |  | 
|  | 542 | pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO); | 
|  | 543 | if (!pdev) { | 
|  | 544 | ret = -ENOMEM; | 
|  | 545 | goto fail; | 
|  | 546 | } | 
|  | 547 |  | 
|  | 548 | pdev->dev.parent = hostdev; | 
|  | 549 | ACPI_COMPANION_SET(&pdev->dev, child); | 
|  | 550 |  | 
|  | 551 | ret = platform_device_add_resources(pdev, res, num_res); | 
|  | 552 | if (ret) | 
|  | 553 | goto fail; | 
|  | 554 |  | 
|  | 555 | ret = platform_device_add_data(pdev, cell->pdata, | 
|  | 556 | cell->pdata_size); | 
|  | 557 | if (ret) | 
|  | 558 | goto fail; | 
|  | 559 |  | 
|  | 560 | ret = platform_device_add(pdev); | 
|  | 561 | if (ret) | 
|  | 562 | goto fail; | 
|  | 563 |  | 
|  | 564 | acpi_device_set_enumerated(child); | 
|  | 565 | } | 
|  | 566 |  | 
|  | 567 | return 0; | 
|  | 568 |  | 
|  | 569 | fail: | 
|  | 570 | hisi_lpc_acpi_remove(hostdev); | 
|  | 571 | return ret; | 
|  | 572 | } | 
|  | 573 |  | 
|  | 574 | static const struct acpi_device_id hisi_lpc_acpi_match[] = { | 
|  | 575 | {"HISI0191"}, | 
|  | 576 | {} | 
|  | 577 | }; | 
|  | 578 | #else | 
|  | 579 | static int hisi_lpc_acpi_probe(struct device *dev) | 
|  | 580 | { | 
|  | 581 | return -ENODEV; | 
|  | 582 | } | 
|  | 583 |  | 
|  | 584 | static void hisi_lpc_acpi_remove(struct device *hostdev) | 
|  | 585 | { | 
|  | 586 | } | 
|  | 587 | #endif // CONFIG_ACPI | 
|  | 588 |  | 
|  | 589 | /* | 
|  | 590 | * hisi_lpc_probe - the probe callback function for hisi lpc host, | 
|  | 591 | *		   will finish all the initialization. | 
|  | 592 | * @pdev: the platform device corresponding to hisi lpc host | 
|  | 593 | * | 
|  | 594 | * Returns 0 on success, non-zero on fail. | 
|  | 595 | */ | 
|  | 596 | static int hisi_lpc_probe(struct platform_device *pdev) | 
|  | 597 | { | 
|  | 598 | struct device *dev = &pdev->dev; | 
|  | 599 | struct acpi_device *acpi_device = ACPI_COMPANION(dev); | 
|  | 600 | struct logic_pio_hwaddr *range; | 
|  | 601 | struct hisi_lpc_dev *lpcdev; | 
|  | 602 | resource_size_t io_end; | 
|  | 603 | struct resource *res; | 
|  | 604 | int ret; | 
|  | 605 |  | 
|  | 606 | lpcdev = devm_kzalloc(dev, sizeof(*lpcdev), GFP_KERNEL); | 
|  | 607 | if (!lpcdev) | 
|  | 608 | return -ENOMEM; | 
|  | 609 |  | 
|  | 610 | spin_lock_init(&lpcdev->cycle_lock); | 
|  | 611 |  | 
|  | 612 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
|  | 613 | lpcdev->membase = devm_ioremap_resource(dev, res); | 
|  | 614 | if (IS_ERR(lpcdev->membase)) | 
|  | 615 | return PTR_ERR(lpcdev->membase); | 
|  | 616 |  | 
|  | 617 | range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL); | 
|  | 618 | if (!range) | 
|  | 619 | return -ENOMEM; | 
|  | 620 |  | 
|  | 621 | range->fwnode = dev->fwnode; | 
|  | 622 | range->flags = LOGIC_PIO_INDIRECT; | 
|  | 623 | range->size = PIO_INDIRECT_SIZE; | 
|  | 624 | range->hostdata = lpcdev; | 
|  | 625 | range->ops = &hisi_lpc_ops; | 
|  | 626 | lpcdev->io_host = range; | 
|  | 627 |  | 
|  | 628 | ret = logic_pio_register_range(range); | 
|  | 629 | if (ret) { | 
|  | 630 | dev_err(dev, "register IO range failed (%d)!\n", ret); | 
|  | 631 | return ret; | 
|  | 632 | } | 
|  | 633 |  | 
|  | 634 | /* register the LPC host PIO resources */ | 
|  | 635 | if (acpi_device) | 
|  | 636 | ret = hisi_lpc_acpi_probe(dev); | 
|  | 637 | else | 
|  | 638 | ret = of_platform_populate(dev->of_node, NULL, NULL, dev); | 
|  | 639 | if (ret) { | 
|  | 640 | logic_pio_unregister_range(range); | 
|  | 641 | return ret; | 
|  | 642 | } | 
|  | 643 |  | 
|  | 644 | dev_set_drvdata(dev, lpcdev); | 
|  | 645 |  | 
|  | 646 | io_end = lpcdev->io_host->io_start + lpcdev->io_host->size; | 
|  | 647 | dev_info(dev, "registered range [%pa - %pa]\n", | 
|  | 648 | &lpcdev->io_host->io_start, &io_end); | 
|  | 649 |  | 
|  | 650 | return ret; | 
|  | 651 | } | 
|  | 652 |  | 
|  | 653 | static int hisi_lpc_remove(struct platform_device *pdev) | 
|  | 654 | { | 
|  | 655 | struct device *dev = &pdev->dev; | 
|  | 656 | struct acpi_device *acpi_device = ACPI_COMPANION(dev); | 
|  | 657 | struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev); | 
|  | 658 | struct logic_pio_hwaddr *range = lpcdev->io_host; | 
|  | 659 |  | 
|  | 660 | if (acpi_device) | 
|  | 661 | hisi_lpc_acpi_remove(dev); | 
|  | 662 | else | 
|  | 663 | of_platform_depopulate(dev); | 
|  | 664 |  | 
|  | 665 | logic_pio_unregister_range(range); | 
|  | 666 |  | 
|  | 667 | return 0; | 
|  | 668 | } | 
|  | 669 |  | 
|  | 670 | static const struct of_device_id hisi_lpc_of_match[] = { | 
|  | 671 | { .compatible = "hisilicon,hip06-lpc", }, | 
|  | 672 | { .compatible = "hisilicon,hip07-lpc", }, | 
|  | 673 | {} | 
|  | 674 | }; | 
|  | 675 |  | 
|  | 676 | static struct platform_driver hisi_lpc_driver = { | 
|  | 677 | .driver = { | 
|  | 678 | .name           = DRV_NAME, | 
|  | 679 | .of_match_table = hisi_lpc_of_match, | 
|  | 680 | .acpi_match_table = ACPI_PTR(hisi_lpc_acpi_match), | 
|  | 681 | }, | 
|  | 682 | .probe = hisi_lpc_probe, | 
|  | 683 | .remove = hisi_lpc_remove, | 
|  | 684 | }; | 
|  | 685 | builtin_platform_driver(hisi_lpc_driver); |