diff options
Diffstat (limited to 'drivers')
387 files changed, 24574 insertions, 4710 deletions
diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c index b43f4459a4f6..ea04a8c69215 100644 --- a/drivers/acpi/platform_profile.c +++ b/drivers/acpi/platform_profile.c @@ -37,6 +37,7 @@ static const char * const profile_names[] = { [PLATFORM_PROFILE_BALANCED] = "balanced", [PLATFORM_PROFILE_BALANCED_PERFORMANCE] = "balanced-performance", [PLATFORM_PROFILE_PERFORMANCE] = "performance", + [PLATFORM_PROFILE_MAX_POWER] = "max-power", [PLATFORM_PROFILE_CUSTOM] = "custom", }; static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST); @@ -506,7 +507,8 @@ int platform_profile_cycle(void) if (err) return err; - if (profile == PLATFORM_PROFILE_CUSTOM || + if (profile == PLATFORM_PROFILE_MAX_POWER || + profile == PLATFORM_PROFILE_CUSTOM || profile == PLATFORM_PROFILE_LAST) return -EINVAL; @@ -515,7 +517,8 @@ int platform_profile_cycle(void) if (err) return err; - /* never iterate into a custom if all drivers supported it */ + /* never iterate into a custom or max power if all drivers supported it */ + clear_bit(PLATFORM_PROFILE_MAX_POWER, data.aggregate); clear_bit(PLATFORM_PROFILE_CUSTOM, data.aggregate); next = find_next_bit_wrap(data.aggregate, diff --git a/drivers/base/power/runtime-test.c b/drivers/base/power/runtime-test.c index 477feca804c7..1535ad2b0264 100644 --- a/drivers/base/power/runtime-test.c +++ b/drivers/base/power/runtime-test.c @@ -38,10 +38,6 @@ static void pm_runtime_already_suspended_test(struct kunit *test) KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); pm_runtime_get_noresume(dev); - KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); /* no wakeup needed */ - pm_runtime_put(dev); - - pm_runtime_get_noresume(dev); KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync(dev)); KUNIT_EXPECT_EQ(test, 1, pm_runtime_suspend(dev)); @@ -174,7 +170,7 @@ static void pm_runtime_error_test(struct kunit *test) KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); KUNIT_EXPECT_EQ(test, 0, pm_runtime_get(dev)); - KUNIT_EXPECT_EQ(test, 1, pm_runtime_barrier(dev)); /* resume was pending */ + pm_runtime_barrier(dev); pm_runtime_put(dev); pm_runtime_suspend(dev); /* flush the put(), to suspend */ KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); @@ -225,7 +221,7 @@ static void pm_runtime_probe_active_test(struct kunit *test) KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); /* Nothing to flush. We stay active. */ - KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); + pm_runtime_barrier(dev); KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); /* Ask for idle? Now we suspend. */ diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 62707738caa4..84676cc24221 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1467,30 +1467,20 @@ static void __pm_runtime_barrier(struct device *dev) * Next, make sure that all pending requests for the device have been flushed * from pm_wq and wait for all runtime PM operations involving the device in * progress to complete. - * - * Return value: - * 1, if there was a resume request pending and the device had to be woken up, - * 0, otherwise */ -int pm_runtime_barrier(struct device *dev) +void pm_runtime_barrier(struct device *dev) { - int retval = 0; - pm_runtime_get_noresume(dev); spin_lock_irq(&dev->power.lock); if (dev->power.request_pending - && dev->power.request == RPM_REQ_RESUME) { + && dev->power.request == RPM_REQ_RESUME) rpm_resume(dev, 0); - retval = 1; - } __pm_runtime_barrier(dev); spin_unlock_irq(&dev->power.lock); pm_runtime_put_noidle(dev); - - return retval; } EXPORT_SYMBOL_GPL(pm_runtime_barrier); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 77d694448990..858320b6ebb7 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -316,9 +316,6 @@ config BLK_DEV_RBD tristate "Rados block device (RBD)" depends on INET && BLOCK select CEPH_LIB - select CRC32 - select CRYPTO_AES - select CRYPTO help Say Y here if you want include the Rados block device, which stripes a block device over objects stored in the Ceph distributed object diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ebe751f39742..272bc608e528 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -348,11 +348,10 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, struct file *file = lo->lo_backing_file; struct bio_vec tmp; unsigned int offset; - int nr_bvec = 0; + unsigned int nr_bvec; int ret; - rq_for_each_bvec(tmp, rq, rq_iter) - nr_bvec++; + nr_bvec = blk_rq_nr_bvec(rq); if (rq->bio != rq->biotail) { diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 2c715df63f23..df9831783a13 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -926,6 +926,7 @@ static size_t ublk_copy_user_pages(const struct request *req, size_t done = 0; rq_for_each_segment(bv, req, iter) { + unsigned len; void *bv_buf; size_t copied; @@ -934,18 +935,17 @@ static size_t ublk_copy_user_pages(const struct request *req, continue; } - bv.bv_offset += offset; - bv.bv_len -= offset; - bv_buf = bvec_kmap_local(&bv); + len = bv.bv_len - offset; + bv_buf = kmap_local_page(bv.bv_page) + bv.bv_offset + offset; if (dir == ITER_DEST) - copied = copy_to_iter(bv_buf, bv.bv_len, uiter); + copied = copy_to_iter(bv_buf, len, uiter); else - copied = copy_from_iter(bv_buf, bv.bv_len, uiter); + copied = copy_from_iter(bv_buf, len, uiter); kunmap_local(bv_buf); done += copied; - if (copied < bv.bv_len) + if (copied < len) break; offset = 0; @@ -3673,6 +3673,19 @@ exit: return ret; } +static bool ublk_ctrl_uring_cmd_may_sleep(u32 cmd_op) +{ + switch (_IOC_NR(cmd_op)) { + case UBLK_CMD_GET_QUEUE_AFFINITY: + case UBLK_CMD_GET_DEV_INFO: + case UBLK_CMD_GET_DEV_INFO2: + case _IOC_NR(UBLK_U_CMD_GET_FEATURES): + return false; + default: + return true; + } +} + static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) { @@ -3681,7 +3694,8 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, u32 cmd_op = cmd->cmd_op; int ret = -EINVAL; - if (issue_flags & IO_URING_F_NONBLOCK) + if (ublk_ctrl_uring_cmd_may_sleep(cmd_op) && + issue_flags & IO_URING_F_NONBLOCK) return -EAGAIN; ublk_ctrl_cmd_dump(cmd); diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c index 3f50321aa4a7..77bd6081b244 100644 --- a/drivers/block/zloop.c +++ b/drivers/block/zloop.c @@ -394,7 +394,7 @@ static void zloop_rw(struct zloop_cmd *cmd) struct bio_vec tmp; unsigned long flags; sector_t zone_end; - int nr_bvec = 0; + unsigned int nr_bvec; int ret; atomic_set(&cmd->ref, 2); @@ -487,8 +487,7 @@ static void zloop_rw(struct zloop_cmd *cmd) spin_unlock_irqrestore(&zone->wp_lock, flags); } - rq_for_each_bvec(tmp, rq, rq_iter) - nr_bvec++; + nr_bvec = blk_rq_nr_bvec(rq); if (rq->bio != rq->biotail) { struct bio_vec *bvec; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index b8a74b1798ba..8bb0a119ecd4 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -102,7 +102,7 @@ config ARM_DMA350 config AT_HDMAC tristate "Atmel AHB DMA support" - depends on ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help @@ -143,7 +143,7 @@ config BCM_SBA_RAID config DMA_BCM2835 tristate "BCM2835 DMA engine support" - depends on ARCH_BCM2835 + depends on ARCH_BCM2835 || COMPILE_TEST select DMA_ENGINE select DMA_VIRTUAL_CHANNELS diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 2d147712cbc6..7d226453961f 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -887,7 +887,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan, first = xt->sgl; dev_info(chan2dev(chan), - "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n", + "%s: src=%pad, dest=%pad, numf=%zu, frame_size=%zu, flags=0x%lx\n", __func__, &xt->src_start, &xt->dst_start, xt->numf, xt->frame_size, flags); @@ -1174,7 +1174,7 @@ atc_prep_dma_memset_sg(struct dma_chan *chan, int i; int ret; - dev_vdbg(chan2dev(chan), "%s: v0x%x l0x%zx f0x%lx\n", __func__, + dev_vdbg(chan2dev(chan), "%s: v0x%x l0x%x f0x%lx\n", __func__, value, sg_len, flags); if (unlikely(!sgl || !sg_len)) { @@ -1503,7 +1503,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, unsigned int periods = buf_len / period_len; unsigned int i; - dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%d/%d)\n", + dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%zu/%zu)\n", direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE", &buf_addr, periods, buf_len, period_len); diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 0117bb2e8591..321748e2983e 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -1060,7 +1060,6 @@ static struct platform_driver bcm2835_dma_driver = { module_platform_driver(bcm2835_dma_driver); -MODULE_ALIAS("platform:bcm2835-dma"); MODULE_DESCRIPTION("BCM2835 DMA engine driver"); MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>"); MODULE_LICENSE("GPL"); diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index cee56cd31a61..c63fa52036d7 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -21,8 +21,6 @@ #include "internal.h" -#define DRV_NAME "dw_dmac" - static int dw_probe(struct platform_device *pdev) { const struct dw_dma_chip_pdata *match; @@ -190,7 +188,7 @@ static struct platform_driver dw_driver = { .remove = dw_remove, .shutdown = dw_shutdown, .driver = { - .name = DRV_NAME, + .name = "dw_dmac", .pm = pm_sleep_ptr(&dw_dev_pm_ops), .of_match_table = of_match_ptr(dw_dma_of_id_table), .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table), @@ -211,4 +209,3 @@ module_exit(dw_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 4976d7dde080..a59212758029 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -206,15 +206,19 @@ void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); } -static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width) +static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth src_addr_width, + enum dma_slave_buswidth dst_addr_width) { - u32 val; + u32 src_val, dst_val; - if (addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) - addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) + src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) + dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - val = ffs(addr_width) - 1; - return val | (val << 8); + src_val = ffs(src_addr_width) - 1; + dst_val = ffs(dst_addr_width) - 1; + return dst_val | (src_val << 8); } void fsl_edma_free_desc(struct virt_dma_desc *vdesc) @@ -612,13 +616,19 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( dma_buf_next = dma_addr; if (direction == DMA_MEM_TO_DEV) { + if (!fsl_chan->cfg.src_addr_width) + fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width; fsl_chan->attr = - fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width); + fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width, + fsl_chan->cfg.dst_addr_width); nbytes = fsl_chan->cfg.dst_addr_width * fsl_chan->cfg.dst_maxburst; } else { + if (!fsl_chan->cfg.dst_addr_width) + fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width; fsl_chan->attr = - fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width); + fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width, + fsl_chan->cfg.dst_addr_width); nbytes = fsl_chan->cfg.src_addr_width * fsl_chan->cfg.src_maxburst; } @@ -689,13 +699,19 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg( fsl_desc->dirn = direction; if (direction == DMA_MEM_TO_DEV) { + if (!fsl_chan->cfg.src_addr_width) + fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width; fsl_chan->attr = - fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width); + fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width, + fsl_chan->cfg.dst_addr_width); nbytes = fsl_chan->cfg.dst_addr_width * fsl_chan->cfg.dst_maxburst; } else { + if (!fsl_chan->cfg.dst_addr_width) + fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width; fsl_chan->attr = - fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width); + fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width, + fsl_chan->cfg.dst_addr_width); nbytes = fsl_chan->cfg.src_addr_width * fsl_chan->cfg.src_maxburst; } @@ -766,6 +782,10 @@ struct dma_async_tx_descriptor *fsl_edma_prep_memcpy(struct dma_chan *chan, { struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); struct fsl_edma_desc *fsl_desc; + u32 src_bus_width, dst_bus_width; + + src_bus_width = min_t(u32, DMA_SLAVE_BUSWIDTH_32_BYTES, 1 << (ffs(dma_src) - 1)); + dst_bus_width = min_t(u32, DMA_SLAVE_BUSWIDTH_32_BYTES, 1 << (ffs(dma_dst) - 1)); fsl_desc = fsl_edma_alloc_desc(fsl_chan, 1); if (!fsl_desc) @@ -778,8 +798,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_memcpy(struct dma_chan *chan, /* To match with copy_align and max_seg_size so 1 tcd is enough */ fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[0].vtcd, dma_src, dma_dst, - fsl_edma_get_tcd_attr(DMA_SLAVE_BUSWIDTH_32_BYTES), - 32, len, 0, 1, 1, 32, 0, true, true, false); + fsl_edma_get_tcd_attr(src_bus_width, dst_bus_width), + src_bus_width, len, 0, 1, 1, dst_bus_width, 0, true, + true, false); return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags); } diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 97583c7d51a2..a753b7cbfa7a 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -999,6 +999,5 @@ static void __exit fsl_edma_exit(void) } module_exit(fsl_edma_exit); -MODULE_ALIAS("platform:fsl-edma"); MODULE_DESCRIPTION("Freescale eDMA engine driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index 21e13f1207cb..6ace5bf80c40 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -1296,6 +1296,5 @@ static struct platform_driver fsl_qdma_driver = { module_platform_driver(fsl_qdma_driver); -MODULE_ALIAS("platform:fsl-qdma"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("NXP Layerscape qDMA engine driver"); diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 5cf419fe6b46..c2cdf41b6e57 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -16,6 +16,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand, u32 *status); static void idxd_device_wqs_clear_state(struct idxd_device *idxd); static void idxd_wq_disable_cleanup(struct idxd_wq *wq); +static int idxd_wq_config_write(struct idxd_wq *wq); /* Interrupt control bits */ void idxd_unmask_error_interrupts(struct idxd_device *idxd) @@ -215,14 +216,28 @@ int idxd_wq_disable(struct idxd_wq *wq, bool reset_config) return 0; } + /* + * Disable WQ does not drain address translations, if WQ attributes are + * changed before translations are drained, pending translations can + * be issued using updated WQ attibutes, resulting in invalid + * translations being cached in the device translation cache. + * + * To make sure pending translations are drained before WQ + * attributes are changed, we use a WQ Drain followed by WQ Reset and + * then restore the WQ configuration. + */ + idxd_wq_drain(wq); + operand = BIT(wq->id % 16) | ((wq->id / 16) << 16); - idxd_cmd_exec(idxd, IDXD_CMD_DISABLE_WQ, operand, &status); + idxd_cmd_exec(idxd, IDXD_CMD_RESET_WQ, operand, &status); if (status != IDXD_CMDSTS_SUCCESS) { - dev_dbg(dev, "WQ disable failed: %#x\n", status); + dev_dbg(dev, "WQ reset failed: %#x\n", status); return -ENXIO; } + idxd_wq_config_write(wq); + if (reset_config) idxd_wq_disable_cleanup(wq); clear_bit(wq->id, idxd->wq_enable_map); diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index acc2983e28e0..0f9cd7815f88 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -1034,5 +1034,4 @@ static struct platform_driver k3_pdma_driver = { module_platform_driver(k3_pdma_driver); MODULE_DESCRIPTION("HiSilicon k3 DMA Driver"); -MODULE_ALIAS("platform:k3dma"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index b7fb843c67a6..ba03321eeff7 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -554,8 +554,7 @@ static void mmp_tdma_issue_pending(struct dma_chan *chan) static void mmp_tdma_remove(struct platform_device *pdev) { - if (pdev->dev.of_node) - of_dma_controller_free(pdev->dev.of_node); + of_dma_controller_free(pdev->dev.of_node); } static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev, @@ -743,6 +742,5 @@ module_platform_driver(mmp_tdma_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MMP Two-Channel DMA Driver"); -MODULE_ALIAS("platform:mmp-tdma"); MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>"); diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 765462303de0..334425faac00 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -1500,7 +1500,6 @@ static const struct platform_device_id nbpf_ids[] = { }; MODULE_DEVICE_TABLE(platform, nbpf_ids); -#ifdef CONFIG_PM static int nbpf_runtime_suspend(struct device *dev) { struct nbpf_device *nbpf = dev_get_drvdata(dev); @@ -1513,17 +1512,16 @@ static int nbpf_runtime_resume(struct device *dev) struct nbpf_device *nbpf = dev_get_drvdata(dev); return clk_prepare_enable(nbpf->clk); } -#endif static const struct dev_pm_ops nbpf_pm_ops = { - SET_RUNTIME_PM_OPS(nbpf_runtime_suspend, nbpf_runtime_resume, NULL) + RUNTIME_PM_OPS(nbpf_runtime_suspend, nbpf_runtime_resume, NULL) }; static struct platform_driver nbpf_driver = { .driver = { .name = "dma-nbpf", .of_match_table = nbpf_match, - .pm = &nbpf_pm_ops, + .pm = pm_ptr(&nbpf_pm_ops), }, .id_table = nbpf_ids, .probe = nbpf_probe, diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 8e87738086b2..66bfea1f156d 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1619,7 +1619,8 @@ gpi_peripheral_config(struct dma_chan *chan, struct dma_slave_config *config) } static int gpi_create_i2c_tre(struct gchan *chan, struct gpi_desc *desc, - struct scatterlist *sgl, enum dma_transfer_direction direction) + struct scatterlist *sgl, enum dma_transfer_direction direction, + unsigned long flags) { struct gpi_i2c_config *i2c = chan->config; struct device *dev = chan->gpii->gpi_dev->dev; @@ -1684,6 +1685,9 @@ static int gpi_create_i2c_tre(struct gchan *chan, struct gpi_desc *desc, tre->dword[3] = u32_encode_bits(TRE_TYPE_DMA, TRE_FLAGS_TYPE); tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOT); + + if (!(flags & DMA_PREP_INTERRUPT)) + tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_BEI); } for (i = 0; i < tre_idx; i++) @@ -1827,6 +1831,9 @@ gpi_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, return NULL; } + if (!(flags & DMA_PREP_INTERRUPT) && (nr - nr_tre < 2)) + return NULL; + gpi_desc = kzalloc(sizeof(*gpi_desc), GFP_NOWAIT); if (!gpi_desc) return NULL; @@ -1835,7 +1842,7 @@ gpi_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (gchan->protocol == QCOM_GPI_SPI) { i = gpi_create_spi_tre(gchan, gpi_desc, sgl, direction); } else if (gchan->protocol == QCOM_GPI_I2C) { - i = gpi_create_i2c_tre(gchan, gpi_desc, sgl, direction); + i = gpi_create_i2c_tre(gchan, gpi_desc, sgl, direction, flags); } else { dev_err(dev, "invalid peripheral: %d\n", gchan->protocol); kfree(gpi_desc); diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig index 8184d475a49a..a16c7e83bd14 100644 --- a/drivers/dma/sh/Kconfig +++ b/drivers/dma/sh/Kconfig @@ -50,7 +50,7 @@ config RENESAS_USB_DMAC config RZ_DMAC tristate "Renesas RZ DMA Controller" - depends on ARCH_R7S72100 || ARCH_RZG2L || COMPILE_TEST + depends on ARCH_RENESAS || COMPILE_TEST select RENESAS_DMA select DMA_VIRTUAL_CHANNELS help diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 0c45ce8c74aa..475a347cae1b 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1728,19 +1728,12 @@ static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec, * Power management */ -#ifdef CONFIG_PM -static int rcar_dmac_runtime_suspend(struct device *dev) -{ - return 0; -} - static int rcar_dmac_runtime_resume(struct device *dev) { struct rcar_dmac *dmac = dev_get_drvdata(dev); return rcar_dmac_init(dmac); } -#endif static const struct dev_pm_ops rcar_dmac_pm = { /* @@ -1748,10 +1741,9 @@ static const struct dev_pm_ops rcar_dmac_pm = { * - Wait for the current transfer to complete and stop the device, * - Resume transfers, if any. */ - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(rcar_dmac_runtime_suspend, rcar_dmac_runtime_resume, - NULL) + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + RUNTIME_PM_OPS(NULL, rcar_dmac_runtime_resume, NULL) }; /* ----------------------------------------------------------------------------- @@ -2036,7 +2028,7 @@ MODULE_DEVICE_TABLE(of, rcar_dmac_of_ids); static struct platform_driver rcar_dmac_driver = { .driver = { - .pm = &rcar_dmac_pm, + .pm = pm_ptr(&rcar_dmac_pm), .name = "rcar-dmac", .of_match_table = rcar_dmac_of_ids, }, diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 7e2b6c97fa2f..b42e5a66fd95 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -670,7 +670,6 @@ static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec, * Power management */ -#ifdef CONFIG_PM static int usb_dmac_runtime_suspend(struct device *dev) { struct usb_dmac *dmac = dev_get_drvdata(dev); @@ -691,13 +690,11 @@ static int usb_dmac_runtime_resume(struct device *dev) return usb_dmac_init(dmac); } -#endif /* CONFIG_PM */ static const struct dev_pm_ops usb_dmac_pm = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(usb_dmac_runtime_suspend, usb_dmac_runtime_resume, - NULL) + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + RUNTIME_PM_OPS(usb_dmac_runtime_suspend, usb_dmac_runtime_resume, NULL) }; /* ----------------------------------------------------------------------------- @@ -894,7 +891,7 @@ MODULE_DEVICE_TABLE(of, usb_dmac_of_ids); static struct platform_driver usb_dmac_driver = { .driver = { - .pm = &usb_dmac_pm, + .pm = pm_ptr(&usb_dmac_pm), .name = "usb-dmac", .of_match_table = usb_dmac_of_ids, }, diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 187a090463ce..6207e0b185e1 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -1311,4 +1311,3 @@ MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DMA driver for Spreadtrum"); MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); MODULE_AUTHOR("Eric Long <eric.long@spreadtrum.com>"); -MODULE_ALIAS("platform:sprd-dma"); diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index c65ee0c7bfbd..dc2ab7d16cf2 100644 --- a/drivers/dma/st_fdma.c +++ b/drivers/dma/st_fdma.c @@ -866,4 +866,3 @@ MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("STMicroelectronics FDMA engine driver"); MODULE_AUTHOR("Ludovic.barre <Ludovic.barre@st.com>"); MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index fad896ff29a2..d0e8bb27a03b 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -1230,7 +1230,6 @@ static struct platform_driver tegra_admac_driver = { module_platform_driver(tegra_admac_driver); -MODULE_ALIAS("platform:tegra210-adma"); MODULE_DESCRIPTION("NVIDIA Tegra ADMA driver"); MODULE_AUTHOR("Dara Ramesh <dramesh@nvidia.com>"); MODULE_AUTHOR("Jon Hunter <jonathanh@nvidia.com>"); diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c index 3782d0a187d1..9825f5218137 100644 --- a/drivers/firmware/efi/libstub/loongarch.c +++ b/drivers/firmware/efi/libstub/loongarch.c @@ -72,10 +72,10 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, desc_ver, priv.runtime_map); /* Config Direct Mapping */ - csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); - csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); - csr_write64(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2); - csr_write64(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3); + csr_write(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); + csr_write(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); + csr_write(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2); + csr_write(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3); real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c74da29253e8..bd185482a7fd 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -737,7 +737,6 @@ config GPIO_TB10X depends on ARC_PLAT_TB10X || COMPILE_TEST select GPIO_GENERIC select GENERIC_IRQ_CHIP - select OF_GPIO config GPIO_TEGRA tristate "NVIDIA Tegra GPIO support" @@ -1568,6 +1567,7 @@ config GPIO_QIXIS_FPGA tristate "NXP QIXIS FPGA GPIO support" depends on MFD_SIMPLE_MFD_I2C || COMPILE_TEST select GPIO_REGMAP + select REGMAP_MMIO help This enables support for the GPIOs found in the QIXIS FPGA which is integrated on some NXP Layerscape boards such as LX2160ARDB and diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index b3a26a06260b..5daf962b0323 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -231,7 +231,7 @@ static int gpio_mmio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long mask = gpio_mmio_line2mask(gc, gpio); - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); if (val) chip->sdata |= mask; @@ -262,7 +262,7 @@ static int gpio_mmio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long mask = gpio_mmio_line2mask(gc, gpio); - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); if (val) chip->sdata |= mask; @@ -302,7 +302,7 @@ static void gpio_mmio_set_multiple_single_reg(struct gpio_chip *gc, struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long set_mask, clear_mask; - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); @@ -391,7 +391,7 @@ static int gpio_mmio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - scoped_guard(raw_spinlock, &chip->lock) { + scoped_guard(raw_spinlock_irqsave, &chip->lock) { chip->sdir &= ~gpio_mmio_line2mask(gc, gpio); if (chip->reg_dir_in) @@ -431,7 +431,7 @@ static void gpio_mmio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - guard(raw_spinlock)(&chip->lock); + guard(raw_spinlock_irqsave)(&chip->lock); chip->sdir |= gpio_mmio_line2mask(gc, gpio); diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index e5ba38e65c10..9581bd5ca947 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -338,7 +338,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config config->regmap_irq_line, config->regmap_irq_flags, 0, config->regmap_irq_chip, &gpio->irq_chip_data); if (ret) - goto err_free_bitmap; + goto err_remove_gpiochip; irq_domain = regmap_irq_get_domain(gpio->irq_chip_data); } else diff --git a/drivers/gpio/gpiolib-acpi-quirks.c b/drivers/gpio/gpiolib-acpi-quirks.c index 7b95d1b03361..a0116f004975 100644 --- a/drivers/gpio/gpiolib-acpi-quirks.c +++ b/drivers/gpio/gpiolib-acpi-quirks.c @@ -370,6 +370,28 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_wake = "ASCP1A00:00@8", }, }, + { + /* + * Spurious wakeups, likely from touchpad controller + * Dell Precision 7780 + * Found in BIOS 1.24.1 + * + * Found in touchpad firmware, installed by Dell Touchpad Firmware Update Utility version 1160.4196.9, A01 + * ( Dell-Touchpad-Firmware-Update-Utility_VYGNN_WIN64_1160.4196.9_A00.EXE ), + * released on 11 Jul 2024 + * + * https://lore.kernel.org/linux-i2c/197ae95ffd8.dc819e60457077.7692120488609091556@zohomail.com/ + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Precision"), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7780"), + DMI_MATCH(DMI_BOARD_NAME, "0C6JVW"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "VEN_0488:00@355", + }, + }, {} /* Terminating entry */ }; diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 8bdd107b1ad1..ba4b718d40a0 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -36,6 +36,8 @@ struct gpio_shared_ref { enum gpiod_flags flags; char *con_id; int dev_id; + /* Protects the auxiliary device struct and the lookup table. */ + struct mutex lock; struct auxiliary_device adev; struct gpiod_lookup_table *lookup; }; @@ -49,6 +51,7 @@ struct gpio_shared_entry { unsigned int offset; /* Index in the property value array. */ size_t index; + /* Synchronizes the modification of shared_desc. */ struct mutex lock; struct gpio_shared_desc *shared_desc; struct kref ref; @@ -56,7 +59,6 @@ struct gpio_shared_entry { }; static LIST_HEAD(gpio_shared_list); -static DEFINE_MUTEX(gpio_shared_lock); static DEFINE_IDA(gpio_shared_ida); #if IS_ENABLED(CONFIG_OF) @@ -77,6 +79,10 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node, /* Handle all special nodes that we should ignore. */ static bool gpio_shared_of_node_ignore(struct device_node *node) { + /* Ignore disabled devices. */ + if (!of_device_is_available(node)) + return true; + /* * __symbols__ is a special, internal node and should not be considered * when scanning for shared GPIOs. @@ -183,6 +189,7 @@ static int gpio_shared_of_traverse(struct device_node *curr) ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr)); ref->flags = args.args[1]; + mutex_init(&ref->lock); if (strends(prop->name, "gpios")) suffix = "-gpios"; @@ -254,7 +261,7 @@ static int gpio_shared_make_adev(struct gpio_device *gdev, struct auxiliary_device *adev = &ref->adev; int ret; - lockdep_assert_held(&gpio_shared_lock); + guard(mutex)(&ref->lock); memset(adev, 0, sizeof(*adev)); @@ -369,14 +376,14 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) if (!lookup) return -ENOMEM; - guard(mutex)(&gpio_shared_lock); - list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { if (!device_match_fwnode(consumer, ref->fwnode) && !gpio_shared_dev_is_reset_gpio(consumer, entry, ref)) continue; + guard(mutex)(&ref->lock); + /* We've already done that on a previous request. */ if (ref->lookup) return 0; @@ -395,7 +402,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0, ref->con_id, lflags); - gpiod_add_lookup_table(no_free_ptr(lookup)); + ref->lookup = no_free_ptr(lookup); + gpiod_add_lookup_table(ref->lookup); return 0; } @@ -408,10 +416,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) static void gpio_shared_remove_adev(struct auxiliary_device *adev) { - lockdep_assert_held(&gpio_shared_lock); - - auxiliary_device_uninit(adev); auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); } int gpio_device_setup_shared(struct gpio_device *gdev) @@ -421,8 +427,6 @@ int gpio_device_setup_shared(struct gpio_device *gdev) unsigned long *flags; int ret; - guard(mutex)(&gpio_shared_lock); - list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { if (gdev->dev.parent == &ref->adev.dev) { @@ -479,19 +483,32 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; - guard(mutex)(&gpio_shared_lock); - list_for_each_entry(entry, &gpio_shared_list, list) { if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; + /* + * For some reason if we call synchronize_srcu() in GPIO core, + * descent here and take this mutex and then recursively call + * synchronize_srcu() again from gpiochip_remove() (which is + * totally fine) called after gpio_shared_remove_adev(), + * lockdep prints a false positive deadlock splat. Disable + * lockdep here. + */ + lockdep_off(); list_for_each_entry(ref, &entry->refs, list) { - gpiod_remove_lookup_table(ref->lookup); - kfree(ref->lookup->table[0].key); - kfree(ref->lookup); - ref->lookup = NULL; + guard(mutex)(&ref->lock); + + if (ref->lookup) { + gpiod_remove_lookup_table(ref->lookup); + kfree(ref->lookup->table[0].key); + kfree(ref->lookup); + ref->lookup = NULL; + } + gpio_shared_remove_adev(&ref->adev); } + lockdep_on(); } } @@ -515,8 +532,6 @@ static void gpiod_shared_put(void *data) { struct gpio_shared_entry *entry = data; - lockdep_assert_not_held(&gpio_shared_lock); - kref_put(&entry->ref, gpio_shared_release); } @@ -554,8 +569,6 @@ struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev) struct gpio_shared_entry *entry; int ret; - lockdep_assert_not_held(&gpio_shared_lock); - entry = dev_get_platdata(dev); if (WARN_ON(!entry)) /* Programmer bug */ @@ -590,6 +603,7 @@ EXPORT_SYMBOL_GPL(devm_gpiod_shared_get); static void gpio_shared_drop_ref(struct gpio_shared_ref *ref) { list_del(&ref->list); + mutex_destroy(&ref->lock); kfree(ref->con_id); ida_free(&gpio_shared_ida, ref->dev_id); fwnode_handle_put(ref->fwnode); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index a67285118c37..c362d4dfb5bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1069,7 +1069,9 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, } /* Prepare a TLB flush fence to be attached to PTs */ - if (!params->unlocked) { + if (!params->unlocked && + /* SI doesn't support pasid or KIQ/MES */ + params->adev->family > AMDGPU_FAMILY_SI) { amdgpu_vm_tlb_fence_create(params->adev, vm, fence); /* Makes sure no PD/PT is freed before the flush */ diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c index b107ee80e472..1f6a22983c0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c @@ -265,6 +265,8 @@ static int vcn_v4_0_5_sw_fini(struct amdgpu_ip_block *ip_block) if (amdgpu_sriov_vf(adev)) amdgpu_virt_free_mm_table(adev); + amdgpu_vcn_sysfs_reset_mask_fini(adev); + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { r = amdgpu_vcn_suspend(adev, i); if (r) diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index 0320163b6e74..f98c735b2905 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -3644,14 +3644,18 @@ static const uint32_t cwsr_trap_gfx9_4_3_hex[] = { }; static const uint32_t cwsr_trap_gfx12_hex[] = { - 0xbfa00001, 0xbfa002a2, - 0xb0804009, 0xb8f8f804, + 0xbfa00001, 0xbfa002b2, + 0xb0804009, 0xb8eef81a, + 0xbf880000, 0xb980081a, + 0x00000000, 0xb8f8f804, + 0x9177ff77, 0x0c000000, + 0x846e9a6e, 0x8c776e77, 0x9178ff78, 0x00008c00, 0xb8fbf811, 0x8b6eff78, 0x00004000, 0xbfa10008, 0x8b6eff7b, 0x00000080, 0xbfa20018, 0x8b6ea07b, - 0xbfa20042, 0xbf830010, + 0xbfa2004a, 0xbf830010, 0xb8fbf811, 0xbfa0fffb, 0x8b6eff7b, 0x00000bd0, 0xbfa20010, 0xb8eef812, @@ -3662,28 +3666,32 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0xf0000000, 0xbfa20005, 0x8b6fff6f, 0x00000200, 0xbfa20002, 0x8b6ea07b, - 0xbfa2002c, 0xbefa4d82, + 0xbfa20034, 0xbefa4d82, 0xbf8a0000, 0x84fa887a, 0xbf0d8f7b, 0xbfa10002, 0x8c7bff7b, 0xffff0000, - 0xf4601bbd, 0xf8000010, - 0xbf8a0000, 0x846e976e, - 0x9177ff77, 0x00800000, - 0x8c776e77, 0xf4603bbd, - 0xf8000000, 0xbf8a0000, - 0xf4603ebd, 0xf8000008, - 0xbf8a0000, 0x8bee6e6e, - 0xbfa10001, 0xbe80486e, - 0x8b6eff6d, 0xf0000000, - 0xbfa20009, 0xb8eef811, - 0x8b6eff6e, 0x00000080, - 0xbfa20007, 0x8c78ff78, - 0x00004000, 0x80ec886c, - 0x82ed806d, 0xbfa00002, - 0x806c846c, 0x826d806d, - 0x8b6dff6d, 0x0000ffff, - 0x8bfe7e7e, 0x8bea6a6a, - 0x85788978, 0xb9783244, + 0x8b6eff77, 0x0c000000, + 0x916dff6d, 0x0c000000, + 0x8c6d6e6d, 0xf4601bbd, + 0xf8000010, 0xbf8a0000, + 0x846e976e, 0x9177ff77, + 0x00800000, 0x8c776e77, + 0xf4603bbd, 0xf8000000, + 0xbf8a0000, 0xf4603ebd, + 0xf8000008, 0xbf8a0000, + 0x8bee6e6e, 0xbfa10001, + 0xbe80486e, 0x8b6eff6d, + 0xf0000000, 0xbfa20009, + 0xb8eef811, 0x8b6eff6e, + 0x00000080, 0xbfa20007, + 0x8c78ff78, 0x00004000, + 0x80ec886c, 0x82ed806d, + 0xbfa00002, 0x806c846c, + 0x826d806d, 0x8b6dff6d, + 0x0000ffff, 0x8bfe7e7e, + 0x8bea6a6a, 0x85788978, + 0x936eff77, 0x0002001a, + 0xb96ef81a, 0xb9783244, 0xbe804a6c, 0xb8faf802, 0xbf0d987a, 0xbfa10001, 0xbfb00000, 0x8b6dff6d, @@ -3981,7 +3989,7 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0x008ce800, 0x00000000, 0x807d817d, 0x8070ff70, 0x00000080, 0xbf0a7b7d, - 0xbfa2fff7, 0xbfa0016e, + 0xbfa2fff7, 0xbfa00171, 0xbef4007e, 0x8b75ff7f, 0x0000ffff, 0x8c75ff75, 0x00040000, 0xbef60080, @@ -4163,12 +4171,14 @@ static const uint32_t cwsr_trap_gfx12_hex[] = { 0xf8000074, 0xbf8a0000, 0x8b6dff6d, 0x0000ffff, 0x8bfe7e7e, 0x8bea6a6a, - 0xb97af804, 0xbe804ec2, - 0xbf94fffe, 0xbe804a6c, + 0x936eff77, 0x0002001a, + 0xb96ef81a, 0xb97af804, 0xbe804ec2, 0xbf94fffe, - 0xbfb10000, 0xbf9f0000, + 0xbe804a6c, 0xbe804ec2, + 0xbf94fffe, 0xbfb10000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, + 0xbf9f0000, 0x00000000, }; static const uint32_t cwsr_trap_gfx9_5_0_hex[] = { diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm index 5a1a1b1f897f..07999b4649de 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm @@ -78,9 +78,16 @@ var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SIZE = SQ_WAVE_EXCP_FLAG_PRIV_HOST_TRAP_SHIFT - SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL_INST_SHIFT var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_WAVE_START_SHIFT var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SIZE = 32 - SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT + +var SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT = 0 +var SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE = 2 + var BARRIER_STATE_SIGNAL_OFFSET = 16 var BARRIER_STATE_VALID_OFFSET = 0 +var TTMP11_SCHED_MODE_SHIFT = 26 +var TTMP11_SCHED_MODE_SIZE = 2 +var TTMP11_SCHED_MODE_MASK = 0xC000000 var TTMP11_DEBUG_TRAP_ENABLED_SHIFT = 23 var TTMP11_DEBUG_TRAP_ENABLED_MASK = 0x800000 @@ -160,8 +167,19 @@ L_JUMP_TO_RESTORE: s_branch L_RESTORE L_SKIP_RESTORE: + // Assume most relaxed scheduling mode is set. Save and revert to normal mode. + s_getreg_b32 ttmp2, hwreg(HW_REG_WAVE_SCHED_MODE) + s_wait_alu 0 + s_setreg_imm32_b32 hwreg(HW_REG_WAVE_SCHED_MODE, \ + SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT, SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE), 0 + s_getreg_b32 s_save_state_priv, hwreg(HW_REG_WAVE_STATE_PRIV) //save STATUS since we will change SCC + // Save SCHED_MODE[1:0] into ttmp11[27:26]. + s_andn2_b32 ttmp11, ttmp11, TTMP11_SCHED_MODE_MASK + s_lshl_b32 ttmp2, ttmp2, TTMP11_SCHED_MODE_SHIFT + s_or_b32 ttmp11, ttmp11, ttmp2 + // Clear SPI_PRIO: do not save with elevated priority. // Clear ECC_ERR: prevents SQC store and triggers FATAL_HALT if setreg'd. s_andn2_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_ALWAYS_CLEAR_MASK @@ -238,6 +256,13 @@ L_FETCH_2ND_TRAP: s_cbranch_scc0 L_NO_SIGN_EXTEND_TMA s_or_b32 ttmp15, ttmp15, 0xFFFF0000 L_NO_SIGN_EXTEND_TMA: +#if ASIC_FAMILY == CHIP_GFX12 + // Move SCHED_MODE[1:0] from ttmp11 to unused bits in ttmp1[27:26] (return PC_HI). + // The second-level trap will restore from ttmp1 for backwards compatibility. + s_and_b32 ttmp2, ttmp11, TTMP11_SCHED_MODE_MASK + s_andn2_b32 ttmp1, ttmp1, TTMP11_SCHED_MODE_MASK + s_or_b32 ttmp1, ttmp1, ttmp2 +#endif s_load_dword ttmp2, [ttmp14, ttmp15], 0x10 scope:SCOPE_SYS // debug trap enabled flag s_wait_idle @@ -287,6 +312,10 @@ L_EXIT_TRAP: // STATE_PRIV.BARRIER_COMPLETE may have changed since we read it. // Only restore fields which the trap handler changes. s_lshr_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_SCC_SHIFT + + // Assume relaxed scheduling mode after this point. + restore_sched_mode(ttmp2) + s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV, SQ_WAVE_STATE_PRIV_SCC_SHIFT, \ SQ_WAVE_STATE_PRIV_POISON_ERR_SHIFT - SQ_WAVE_STATE_PRIV_SCC_SHIFT + 1), s_save_state_priv @@ -1043,6 +1072,9 @@ L_SKIP_BARRIER_RESTORE: s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32 s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 + // Assume relaxed scheduling mode after this point. + restore_sched_mode(s_restore_tmp) + s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV), s_restore_state_priv // SCC is included, which is changed by previous salu // Make barrier and LDS state visible to all waves in the group. @@ -1134,3 +1166,8 @@ function valu_sgpr_hazard end #endif end + +function restore_sched_mode(s_tmp) + s_bfe_u32 s_tmp, ttmp11, (TTMP11_SCHED_MODE_SHIFT | (TTMP11_SCHED_MODE_SIZE << 0x10)) + s_setreg_b32 hwreg(HW_REG_WAVE_SCHED_MODE), s_tmp +end diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index f1e7583650c4..80c4fa2b0975 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -409,6 +409,7 @@ static u32 kfd_get_vgpr_size_per_cu(u32 gfxv) vgpr_size = 0x80000; else if (gfxv == 110000 || /* GFX_VERSION_PLUM_BONITO */ gfxv == 110001 || /* GFX_VERSION_WHEAT_NAS */ + gfxv == 110501 || /* GFX_VERSION_GFX1151 */ gfxv == 120000 || /* GFX_VERSION_GFX1200 */ gfxv == 120001) /* GFX_VERSION_GFX1201 */ vgpr_size = 0x60000; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 97c2270f278f..79ea138897fc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1144,30 +1144,48 @@ static int svm_range_split_tail(struct svm_range *prange, uint64_t new_last, struct list_head *insert_list, struct list_head *remap_list) { + unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long start_align = ALIGN(prange->start, 512); + bool huge_page_mapping = last_align_down > start_align; struct svm_range *tail = NULL; - int r = svm_range_split(prange, prange->start, new_last, &tail); + int r; - if (!r) { - list_add(&tail->list, insert_list); - if (!IS_ALIGNED(new_last + 1, 1UL << prange->granularity)) - list_add(&tail->update_list, remap_list); - } - return r; + r = svm_range_split(prange, prange->start, new_last, &tail); + + if (r) + return r; + + list_add(&tail->list, insert_list); + + if (huge_page_mapping && tail->start > start_align && + tail->start < last_align_down && (!IS_ALIGNED(tail->start, 512))) + list_add(&tail->update_list, remap_list); + + return 0; } static int svm_range_split_head(struct svm_range *prange, uint64_t new_start, struct list_head *insert_list, struct list_head *remap_list) { + unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long start_align = ALIGN(prange->start, 512); + bool huge_page_mapping = last_align_down > start_align; struct svm_range *head = NULL; - int r = svm_range_split(prange, new_start, prange->last, &head); + int r; - if (!r) { - list_add(&head->list, insert_list); - if (!IS_ALIGNED(new_start, 1UL << prange->granularity)) - list_add(&head->update_list, remap_list); - } - return r; + r = svm_range_split(prange, new_start, prange->last, &head); + + if (r) + return r; + + list_add(&head->list, insert_list); + + if (huge_page_mapping && head->last + 1 > start_align && + head->last + 1 < last_align_down && (!IS_ALIGNED(head->last, 512))) + list_add(&head->update_list, remap_list); + + return 0; } static void diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 811636af14ea..3eb32d58a120 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -491,6 +491,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->node_props.num_sdma_queues_per_engine); sysfs_show_32bit_prop(buffer, offs, "num_cp_queues", dev->node_props.num_cp_queues); + sysfs_show_32bit_prop(buffer, offs, "cwsr_size", + dev->node_props.cwsr_size); + sysfs_show_32bit_prop(buffer, offs, "ctl_stack_size", + dev->node_props.ctl_stack_size); if (dev->gpu) { log_max_watch_addr = diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index ef97cede9926..bd0403005f37 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -1063,6 +1063,9 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, void amdgpu_dm_update_connector_after_detect( struct amdgpu_dm_connector *aconnector); +void populate_hdmi_info_from_connector(struct drm_hdmi_info *info, + struct dc_edid_caps *edid_caps); + extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs; int amdgpu_dm_process_dmub_aux_transfer_sync(struct dc_context *ctx, unsigned int link_index, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index ac98c746c3de..e5e993d3ef74 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -139,6 +139,9 @@ enum dc_edid_status dm_helpers_parse_edid_caps( edid_caps->edid_hdmi = connector->display_info.is_hdmi; + if (edid_caps->edid_hdmi) + populate_hdmi_info_from_connector(&connector->display_info.hdmi, edid_caps); + apply_edid_quirks(dev, edid_buf, edid_caps); sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads); @@ -990,6 +993,11 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector) return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector); } +void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps) +{ + edid_caps->scdc_present = hdmi->scdc.supported; +} + enum dc_edid_status dm_helpers_read_local_edid( struct dc_context *ctx, struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index dbd1da4d85d3..5e92eaa67aa3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -884,28 +884,26 @@ struct dsc_mst_fairness_params { }; #if defined(CONFIG_DRM_AMD_DC_FP) -static uint64_t kbps_to_pbn(int kbps, bool is_peak_pbn) +static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link) { - uint64_t effective_kbps = (uint64_t)kbps; + u8 link_coding_cap; + uint16_t fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B; - if (is_peak_pbn) { // add 0.6% (1006/1000) overhead into effective kbps - effective_kbps *= 1006; - effective_kbps = div_u64(effective_kbps, 1000); - } + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(dc_link); + if (link_coding_cap == DP_128b_132b_ENCODING) + fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B; - return (uint64_t) DIV64_U64_ROUND_UP(effective_kbps * 64, (54 * 8 * 1000)); + return fec_overhead_multiplier_x1000; } -static uint32_t pbn_to_kbps(unsigned int pbn, bool with_margin) +static int kbps_to_peak_pbn(int kbps, uint16_t fec_overhead_multiplier_x1000) { - uint64_t pbn_effective = (uint64_t)pbn; - - if (with_margin) // deduct 0.6% (994/1000) overhead from effective pbn - pbn_effective *= (1000000 / PEAK_FACTOR_X1000); - else - pbn_effective *= 1000; + u64 peak_kbps = kbps; - return DIV_U64_ROUND_UP(pbn_effective * 8 * 54, 64); + peak_kbps *= 1006; + peak_kbps *= fec_overhead_multiplier_x1000; + peak_kbps = div_u64(peak_kbps, 1000 * 1000); + return (int) DIV64_U64_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000)); } static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params, @@ -976,7 +974,7 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn) dc_dsc_get_default_config_option(param.sink->ctx->dc, &dsc_options); dsc_options.max_target_bpp_limit_override_x16 = drm_connector->display_info.max_dsc_bpp * 16; - kbps = pbn_to_kbps(pbn, false); + kbps = div_u64((u64)pbn * 994 * 8 * 54, 64); dc_dsc_compute_config( param.sink->ctx->dc->res_pool->dscs[0], ¶m.sink->dsc_caps.dsc_dec_caps, @@ -1005,11 +1003,12 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, int link_timeslots_used; int fair_pbn_alloc; int ret = 0; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); for (i = 0; i < count; i++) { if (vars[i + k].dsc_enabled) { initial_slack[i] = - kbps_to_pbn(params[i].bw_range.max_kbps, false) - vars[i + k].pbn; + kbps_to_peak_pbn(params[i].bw_range.max_kbps, fec_overhead_multiplier_x1000) - vars[i + k].pbn; bpp_increased[i] = false; remaining_to_increase += 1; } else { @@ -1105,6 +1104,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, int next_index; int remaining_to_try = 0; int ret; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); int var_pbn; for (i = 0; i < count; i++) { @@ -1137,7 +1137,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC index #%d, try no compression\n", next_index); var_pbn = vars[next_index].pbn; - vars[next_index].pbn = kbps_to_pbn(params[next_index].bw_range.stream_kbps, true); + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps, fec_overhead_multiplier_x1000); ret = drm_dp_atomic_find_time_slots(state, params[next_index].port->mgr, params[next_index].port, @@ -1197,6 +1197,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, int count = 0; int i, k, ret; bool debugfs_overwrite = false; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); struct drm_connector_state *new_conn_state; memset(params, 0, sizeof(params)); @@ -1277,7 +1278,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC Try no compression\n"); for (i = 0; i < count; i++) { vars[i + k].aconnector = params[i].aconnector; - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port, @@ -1299,7 +1300,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, DRM_DEBUG_DRIVER("MST_DSC Try max compression\n"); for (i = 0; i < count; i++) { if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) { - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.min_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = true; vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, @@ -1307,7 +1308,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, if (ret < 0) return ret; } else { - vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, @@ -1762,6 +1763,18 @@ clean_exit: return ret; } +static uint32_t kbps_from_pbn(unsigned int pbn) +{ + uint64_t kbps = (uint64_t)pbn; + + kbps *= (1000000 / PEAK_FACTOR_X1000); + kbps *= 8; + kbps *= 54; + kbps /= 64; + + return (uint32_t)kbps; +} + static bool is_dsc_common_config_possible(struct dc_stream_state *stream, struct dc_dsc_bw_range *bw_range) { @@ -1860,7 +1873,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( dc_link_get_highest_encoding_format(stream->link)); cur_link_settings = stream->link->verified_link_cap; root_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, &cur_link_settings); - virtual_channel_bw_in_kbps = pbn_to_kbps(aconnector->mst_output_port->full_pbn, true); + virtual_channel_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn); /* pick the end to end bw bottleneck */ end_to_end_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps); @@ -1913,7 +1926,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( immediate_upstream_port = aconnector->mst_output_port->parent->port_parent; if (immediate_upstream_port) { - virtual_channel_bw_in_kbps = pbn_to_kbps(immediate_upstream_port->full_pbn, true); + virtual_channel_bw_in_kbps = kbps_from_pbn(immediate_upstream_port->full_pbn); virtual_channel_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps); } else { /* For topology LCT 1 case - only one mstb*/ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 922f23557f5d..0971dfa25845 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -86,7 +86,7 @@ uint8_t dc_plane_get_pipe_mask(struct dc_state *dc_state, const struct dc_plane struct dc_plane_state *dc_create_plane_state(const struct dc *dc) { struct dc_plane_state *plane_state = kvzalloc(sizeof(*plane_state), - GFP_KERNEL); + GFP_ATOMIC); if (NULL == plane_state) return NULL; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c index c468f492b876..09303c282495 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c @@ -6711,6 +6711,76 @@ static noinline_for_stack void dml_prefetch_check(struct display_mode_lib_st *mo } // for j } +static noinline_for_stack void set_vm_row_and_swath_parameters(struct display_mode_lib_st *mode_lib) +{ + struct CalculateVMRowAndSwath_params_st *CalculateVMRowAndSwath_params = &mode_lib->scratch.CalculateVMRowAndSwath_params; + struct dml_core_mode_support_locals_st *s = &mode_lib->scratch.dml_core_mode_support_locals; + + CalculateVMRowAndSwath_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes; + CalculateVMRowAndSwath_params->myPipe = s->SurfParameters; + CalculateVMRowAndSwath_params->SurfaceSizeInMALL = mode_lib->ms.SurfaceSizeInMALL; + CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsLuma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_luma; + CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsChroma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_chroma; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ms.ip.dcc_meta_buffer_size_bytes; + CalculateVMRowAndSwath_params->UseMALLForStaticScreen = mode_lib->ms.cache_display_cfg.plane.UseMALLForStaticScreen; + CalculateVMRowAndSwath_params->UseMALLForPStateChange = mode_lib->ms.cache_display_cfg.plane.UseMALLForPStateChange; + CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->ms.soc.mall_allocated_for_dcn_mbytes; + CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthYThisState; + CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthCThisState; + CalculateVMRowAndSwath_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable; + CalculateVMRowAndSwath_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; + CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; + CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; + CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; + CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; + CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; + CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeNotExceeded = mode_lib->ms.DCCMetaBufferSizeNotExceededPerState; + CalculateVMRowAndSwath_params->dpte_row_width_luma_ub = s->dummy_integer_array[0]; + CalculateVMRowAndSwath_params->dpte_row_width_chroma_ub = s->dummy_integer_array[1]; + CalculateVMRowAndSwath_params->dpte_row_height_luma = mode_lib->ms.dpte_row_height; + CalculateVMRowAndSwath_params->dpte_row_height_chroma = mode_lib->ms.dpte_row_height_chroma; + CalculateVMRowAndSwath_params->dpte_row_height_linear_luma = s->dummy_integer_array[2]; // VBA_DELTA + CalculateVMRowAndSwath_params->dpte_row_height_linear_chroma = s->dummy_integer_array[3]; // VBA_DELTA + CalculateVMRowAndSwath_params->meta_req_width = s->dummy_integer_array[4]; + CalculateVMRowAndSwath_params->meta_req_width_chroma = s->dummy_integer_array[5]; + CalculateVMRowAndSwath_params->meta_req_height = s->dummy_integer_array[6]; + CalculateVMRowAndSwath_params->meta_req_height_chroma = s->dummy_integer_array[7]; + CalculateVMRowAndSwath_params->meta_row_width = s->dummy_integer_array[8]; + CalculateVMRowAndSwath_params->meta_row_width_chroma = s->dummy_integer_array[9]; + CalculateVMRowAndSwath_params->meta_row_height = mode_lib->ms.meta_row_height; + CalculateVMRowAndSwath_params->meta_row_height_chroma = mode_lib->ms.meta_row_height_chroma; + CalculateVMRowAndSwath_params->vm_group_bytes = s->dummy_integer_array[10]; + CalculateVMRowAndSwath_params->dpte_group_bytes = mode_lib->ms.dpte_group_bytes; + CalculateVMRowAndSwath_params->PixelPTEReqWidthY = s->dummy_integer_array[11]; + CalculateVMRowAndSwath_params->PixelPTEReqHeightY = s->dummy_integer_array[12]; + CalculateVMRowAndSwath_params->PTERequestSizeY = s->dummy_integer_array[13]; + CalculateVMRowAndSwath_params->PixelPTEReqWidthC = s->dummy_integer_array[14]; + CalculateVMRowAndSwath_params->PixelPTEReqHeightC = s->dummy_integer_array[15]; + CalculateVMRowAndSwath_params->PTERequestSizeC = s->dummy_integer_array[16]; + CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_l = s->dummy_integer_array[17]; + CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_l = s->dummy_integer_array[18]; + CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_c = s->dummy_integer_array[19]; + CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_c = s->dummy_integer_array[20]; + CalculateVMRowAndSwath_params->PrefetchSourceLinesY = mode_lib->ms.PrefetchLinesYThisState; + CalculateVMRowAndSwath_params->PrefetchSourceLinesC = mode_lib->ms.PrefetchLinesCThisState; + CalculateVMRowAndSwath_params->VInitPreFillY = mode_lib->ms.PrefillY; + CalculateVMRowAndSwath_params->VInitPreFillC = mode_lib->ms.PrefillC; + CalculateVMRowAndSwath_params->MaxNumSwathY = mode_lib->ms.MaxNumSwY; + CalculateVMRowAndSwath_params->MaxNumSwathC = mode_lib->ms.MaxNumSwC; + CalculateVMRowAndSwath_params->meta_row_bw = mode_lib->ms.meta_row_bandwidth_this_state; + CalculateVMRowAndSwath_params->dpte_row_bw = mode_lib->ms.dpte_row_bandwidth_this_state; + CalculateVMRowAndSwath_params->PixelPTEBytesPerRow = mode_lib->ms.DPTEBytesPerRowThisState; + CalculateVMRowAndSwath_params->PDEAndMetaPTEBytesFrame = mode_lib->ms.PDEAndMetaPTEBytesPerFrameThisState; + CalculateVMRowAndSwath_params->MetaRowByte = mode_lib->ms.MetaRowBytesThisState; + CalculateVMRowAndSwath_params->use_one_row_for_frame = mode_lib->ms.use_one_row_for_frame_this_state; + CalculateVMRowAndSwath_params->use_one_row_for_frame_flip = mode_lib->ms.use_one_row_for_frame_flip_this_state; + CalculateVMRowAndSwath_params->UsesMALLForStaticScreen = s->dummy_boolean_array[0]; + CalculateVMRowAndSwath_params->PTE_BUFFER_MODE = s->dummy_boolean_array[1]; + CalculateVMRowAndSwath_params->BIGK_FRAGMENT_SIZE = s->dummy_integer_array[21]; +} + /// @brief The Mode Support function. dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) { @@ -7683,69 +7753,7 @@ dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) s->SurfParameters[k].SwathHeightC = mode_lib->ms.SwathHeightCThisState[k]; } - CalculateVMRowAndSwath_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes; - CalculateVMRowAndSwath_params->myPipe = s->SurfParameters; - CalculateVMRowAndSwath_params->SurfaceSizeInMALL = mode_lib->ms.SurfaceSizeInMALL; - CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsLuma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_luma; - CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsChroma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_chroma; - CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ms.ip.dcc_meta_buffer_size_bytes; - CalculateVMRowAndSwath_params->UseMALLForStaticScreen = mode_lib->ms.cache_display_cfg.plane.UseMALLForStaticScreen; - CalculateVMRowAndSwath_params->UseMALLForPStateChange = mode_lib->ms.cache_display_cfg.plane.UseMALLForPStateChange; - CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->ms.soc.mall_allocated_for_dcn_mbytes; - CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthYThisState; - CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthCThisState; - CalculateVMRowAndSwath_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable; - CalculateVMRowAndSwath_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; - CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; - CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; - CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; - CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; - CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; - CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState; - CalculateVMRowAndSwath_params->DCCMetaBufferSizeNotExceeded = mode_lib->ms.DCCMetaBufferSizeNotExceededPerState; - CalculateVMRowAndSwath_params->dpte_row_width_luma_ub = s->dummy_integer_array[0]; - CalculateVMRowAndSwath_params->dpte_row_width_chroma_ub = s->dummy_integer_array[1]; - CalculateVMRowAndSwath_params->dpte_row_height_luma = mode_lib->ms.dpte_row_height; - CalculateVMRowAndSwath_params->dpte_row_height_chroma = mode_lib->ms.dpte_row_height_chroma; - CalculateVMRowAndSwath_params->dpte_row_height_linear_luma = s->dummy_integer_array[2]; // VBA_DELTA - CalculateVMRowAndSwath_params->dpte_row_height_linear_chroma = s->dummy_integer_array[3]; // VBA_DELTA - CalculateVMRowAndSwath_params->meta_req_width = s->dummy_integer_array[4]; - CalculateVMRowAndSwath_params->meta_req_width_chroma = s->dummy_integer_array[5]; - CalculateVMRowAndSwath_params->meta_req_height = s->dummy_integer_array[6]; - CalculateVMRowAndSwath_params->meta_req_height_chroma = s->dummy_integer_array[7]; - CalculateVMRowAndSwath_params->meta_row_width = s->dummy_integer_array[8]; - CalculateVMRowAndSwath_params->meta_row_width_chroma = s->dummy_integer_array[9]; - CalculateVMRowAndSwath_params->meta_row_height = mode_lib->ms.meta_row_height; - CalculateVMRowAndSwath_params->meta_row_height_chroma = mode_lib->ms.meta_row_height_chroma; - CalculateVMRowAndSwath_params->vm_group_bytes = s->dummy_integer_array[10]; - CalculateVMRowAndSwath_params->dpte_group_bytes = mode_lib->ms.dpte_group_bytes; - CalculateVMRowAndSwath_params->PixelPTEReqWidthY = s->dummy_integer_array[11]; - CalculateVMRowAndSwath_params->PixelPTEReqHeightY = s->dummy_integer_array[12]; - CalculateVMRowAndSwath_params->PTERequestSizeY = s->dummy_integer_array[13]; - CalculateVMRowAndSwath_params->PixelPTEReqWidthC = s->dummy_integer_array[14]; - CalculateVMRowAndSwath_params->PixelPTEReqHeightC = s->dummy_integer_array[15]; - CalculateVMRowAndSwath_params->PTERequestSizeC = s->dummy_integer_array[16]; - CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_l = s->dummy_integer_array[17]; - CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_l = s->dummy_integer_array[18]; - CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_c = s->dummy_integer_array[19]; - CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_c = s->dummy_integer_array[20]; - CalculateVMRowAndSwath_params->PrefetchSourceLinesY = mode_lib->ms.PrefetchLinesYThisState; - CalculateVMRowAndSwath_params->PrefetchSourceLinesC = mode_lib->ms.PrefetchLinesCThisState; - CalculateVMRowAndSwath_params->VInitPreFillY = mode_lib->ms.PrefillY; - CalculateVMRowAndSwath_params->VInitPreFillC = mode_lib->ms.PrefillC; - CalculateVMRowAndSwath_params->MaxNumSwathY = mode_lib->ms.MaxNumSwY; - CalculateVMRowAndSwath_params->MaxNumSwathC = mode_lib->ms.MaxNumSwC; - CalculateVMRowAndSwath_params->meta_row_bw = mode_lib->ms.meta_row_bandwidth_this_state; - CalculateVMRowAndSwath_params->dpte_row_bw = mode_lib->ms.dpte_row_bandwidth_this_state; - CalculateVMRowAndSwath_params->PixelPTEBytesPerRow = mode_lib->ms.DPTEBytesPerRowThisState; - CalculateVMRowAndSwath_params->PDEAndMetaPTEBytesFrame = mode_lib->ms.PDEAndMetaPTEBytesPerFrameThisState; - CalculateVMRowAndSwath_params->MetaRowByte = mode_lib->ms.MetaRowBytesThisState; - CalculateVMRowAndSwath_params->use_one_row_for_frame = mode_lib->ms.use_one_row_for_frame_this_state; - CalculateVMRowAndSwath_params->use_one_row_for_frame_flip = mode_lib->ms.use_one_row_for_frame_flip_this_state; - CalculateVMRowAndSwath_params->UsesMALLForStaticScreen = s->dummy_boolean_array[0]; - CalculateVMRowAndSwath_params->PTE_BUFFER_MODE = s->dummy_boolean_array[1]; - CalculateVMRowAndSwath_params->BIGK_FRAGMENT_SIZE = s->dummy_integer_array[21]; + set_vm_row_and_swath_parameters(mode_lib); CalculateVMRowAndSwath(&mode_lib->scratch, CalculateVMRowAndSwath_params); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 8fe399939220..4986f12dc9df 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -1484,9 +1484,6 @@ void build_audio_output( state->clk_mgr); } - audio_output->pll_info.feed_back_divider = - pipe_ctx->pll_settings.feedback_divider; - audio_output->pll_info.dto_source = translate_to_dto_source( pipe_ctx->stream_res.tg->inst + 1); diff --git a/drivers/gpu/drm/amd/display/include/audio_types.h b/drivers/gpu/drm/amd/display/include/audio_types.h index e4a26143f14c..6699ad4fa825 100644 --- a/drivers/gpu/drm/amd/display/include/audio_types.h +++ b/drivers/gpu/drm/amd/display/include/audio_types.h @@ -47,15 +47,15 @@ struct audio_crtc_info { uint32_t h_total; uint32_t h_active; uint32_t v_active; - uint32_t pixel_repetition; uint32_t requested_pixel_clock_100Hz; /* in 100Hz */ uint32_t calculated_pixel_clock_100Hz; /* in 100Hz */ - uint32_t refresh_rate; + uint32_t dsc_bits_per_pixel; + uint32_t dsc_num_slices; enum dc_color_depth color_depth; enum dc_pixel_encoding pixel_encoding; + uint16_t refresh_rate; + uint8_t pixel_repetition; bool interlaced; - uint32_t dsc_bits_per_pixel; - uint32_t dsc_num_slices; }; struct azalia_clock_info { uint32_t pixel_clock_in_10khz; @@ -78,11 +78,9 @@ enum audio_dto_source { struct audio_pll_info { uint32_t audio_dto_source_clock_in_khz; - uint32_t feed_back_divider; + uint32_t ss_percentage; enum audio_dto_source dto_source; bool ss_enabled; - uint32_t ss_percentage; - uint32_t ss_percentage_divider; }; struct audio_channel_associate_info { diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 033c44326552..fffb47b62f43 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -429,7 +429,14 @@ static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx) */ ret = regmap_read(ctx->regmap, REG_IRQ_STAT, &irq_stat); - if (ret || irq_stat) { + + /* + * Some hardware (Toradex Verdin AM62) is known to report the + * PLL_UNLOCK error interrupt while working without visible + * problems. In lack of a reliable way to discriminate such cases + * from user-visible PLL_UNLOCK cases, ignore that bit entirely. + */ + if (ret || irq_stat & ~REG_IRQ_STAT_CHA_PLL_UNLOCK) { /* * IRQ acknowledged is not always possible (the bridge can be in * a state where it doesn't answer anymore). To prevent an @@ -654,7 +661,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, if (ctx->irq) { /* Enable irq to detect errors */ regmap_write(ctx->regmap, REG_IRQ_GLOBAL, REG_IRQ_GLOBAL_IRQ_EN); - regmap_write(ctx->regmap, REG_IRQ_EN, 0xff); + regmap_write(ctx->regmap, REG_IRQ_EN, 0xff & ~REG_IRQ_EN_CHA_PLL_UNLOCK_EN); } else { /* Use the polling task */ sn65dsi83_monitor_start(ctx); diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c index 12d8307997a0..eb56ba234796 100644 --- a/drivers/gpu/drm/drm_gem_dma_helper.c +++ b/drivers/gpu/drm/drm_gem_dma_helper.c @@ -308,7 +308,7 @@ int drm_gem_dma_dumb_create(struct drm_file *file_priv, struct drm_gem_dma_object *dma_obj; int ret; - ret = drm_mode_size_dumb(drm, args, SZ_8, 0); + ret = drm_mode_size_dumb(drm, args, 0, 0); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index dc94a27710e5..93b9cff89080 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -559,7 +559,7 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, { int ret; - ret = drm_mode_size_dumb(dev, args, SZ_8, 0); + ret = drm_mode_size_dumb(dev, args, 0, 0); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index ce76c55913f7..b143589717e6 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -338,14 +338,14 @@ static int drm_plane_create_hotspot_properties(struct drm_plane *plane) prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X", INT_MIN, INT_MAX); - if (IS_ERR(prop_x)) - return PTR_ERR(prop_x); + if (!prop_x) + return -ENOMEM; prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y", INT_MIN, INT_MAX); - if (IS_ERR(prop_y)) { + if (!prop_y) { drm_property_destroy(plane->dev, prop_x); - return PTR_ERR(prop_y); + return -ENOMEM; } drm_object_attach_property(&plane->base, prop_x, 0); diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 9cd03e2adeb2..44f4fcce526e 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -288,13 +288,18 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, drm_framebuffer_put(&fb->base); fb = NULL; } + + wakeref = intel_display_rpm_get(display); + if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); fb = __intel_fbdev_fb_alloc(display, sizes); - if (IS_ERR(fb)) - return PTR_ERR(fb); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); + goto out_unlock; + } } else { drm_dbg_kms(display->drm, "re-using BIOS fb\n"); prealloc = true; @@ -302,8 +307,6 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, sizes->fb_height = fb->base.height; } - wakeref = intel_display_rpm_get(display); - /* Pin the GGTT vma for our access via info->screen_base. * This also validates that any existing fb inherited from the * BIOS is suitable for own access. diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index b3b75be9ced5..e9a4e6090fe0 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -72,7 +72,7 @@ struct intel_memory_region { u16 instance; enum intel_region_id id; char name[16]; - char uabi_name[16]; + char uabi_name[20]; bool private; /* not for userspace */ struct { diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 951d715dea30..d019177462cf 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -161,6 +161,30 @@ static void mgag200_set_startadd(struct mga_device *mdev, WREG_ECRT(0x00, crtcext0); } +/* + * Set the opmode for the hardware swapper for Big-Endian processor + * support for the frame buffer aperture and DMAWIN space. + */ +static void mgag200_set_datasiz(struct mga_device *mdev, u32 format) +{ +#if defined(__BIG_ENDIAN) + u32 opmode = RREG32(MGAREG_OPMODE); + + opmode &= ~(GENMASK(17, 16) | GENMASK(9, 8) | GENMASK(3, 2)); + + /* Big-endian byte-swapping */ + switch (format) { + case DRM_FORMAT_RGB565: + opmode |= 0x10100; + break; + case DRM_FORMAT_XRGB8888: + opmode |= 0x20200; + break; + } + WREG32(MGAREG_OPMODE, opmode); +#endif +} + void mgag200_init_registers(struct mga_device *mdev) { u8 crtc11, misc; @@ -496,6 +520,7 @@ void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_helper_damage_iter iter; struct drm_rect damage; + mgag200_set_datasiz(mdev, fb->format->format); drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); drm_atomic_for_each_plane_damage(&iter, &damage) { mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); diff --git a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c index e2bf99c43336..a60209097a20 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c +++ b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c @@ -94,26 +94,6 @@ fail_unregister: return err; } -/** - * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder - * @drm_encoder: Encoder to be unregistered. - * - * This should be called from the @destroy method of an I2C slave - * encoder driver once I2C access is no longer needed. - */ -void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) -{ - struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); - struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); - struct module *module = client->dev.driver->owner; - - i2c_unregister_device(client); - encoder->i2c_client = NULL; - - module_put(module); -} -EXPORT_SYMBOL(nouveau_i2c_encoder_destroy); - /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: */ diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h index 31334aa90781..869820701a56 100644 --- a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h +++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h @@ -202,7 +202,24 @@ static inline struct i2c_client *nouveau_i2c_encoder_get_client(struct drm_encod return to_encoder_i2c(encoder)->i2c_client; } -void nouveau_i2c_encoder_destroy(struct drm_encoder *encoder); +/** + * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder + * @drm_encoder: Encoder to be unregistered. + * + * This should be called from the @destroy method of an I2C slave + * encoder driver once I2C access is no longer needed. + */ +static __always_inline void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) +{ + struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); + struct module *module = client->dev.driver->owner; + + i2c_unregister_device(client); + encoder->i2c_client = NULL; + + module_put(module); +} /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h index 226c7ec56b8e..b8b97e10ae83 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h @@ -73,6 +73,10 @@ struct nvkm_gsp { const struct firmware *bl; const struct firmware *rm; + + struct { + struct nvkm_falcon_fw sb; + } falcon; } fws; struct nvkm_firmware fw; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 869d4335c0f4..4a193b7d6d9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -183,11 +183,11 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha fctx->context = drm->runl[chan->runlist].context_base + chan->chid; if (chan == drm->cechan) - strcpy(fctx->name, "copy engine channel"); + strscpy(fctx->name, "copy engine channel"); else if (chan == drm->channel) - strcpy(fctx->name, "generic kernel channel"); + strscpy(fctx->name, "generic kernel channel"); else - strcpy(fctx->name, cli->name); + strscpy(fctx->name, cli->name); kref_init(&fctx->fence_ref); if (!priv->uevent) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 5c07a9ee8b77..34effe6d86ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -125,7 +125,7 @@ nouveau_hwmon_get_pwm1_max(struct device *d, if (ret < 0) return ret; - return sprintf(buf, "%i\n", ret); + return sysfs_emit(buf, "%i\n", ret); } static ssize_t @@ -141,7 +141,7 @@ nouveau_hwmon_get_pwm1_min(struct device *d, if (ret < 0) return ret; - return sprintf(buf, "%i\n", ret); + return sysfs_emit(buf, "%i\n", ret); } static ssize_t diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c index 5b721bd9d799..503760246660 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c @@ -259,18 +259,16 @@ nvkm_gsp_fwsec_v3(struct nvkm_gsp *gsp, const char *name, } static int -nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) +nvkm_gsp_fwsec_init(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw, const char *name, u32 init_cmd) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; const union nvfw_falcon_ucode_desc *desc; struct nvbios_pmuE flcn_ucode; - u8 idx, ver, hdr; u32 data; u16 size, vers; - struct nvkm_falcon_fw fw = {}; - u32 mbox0 = 0; + u8 idx, ver, hdr; int ret; /* Lookup in VBIOS. */ @@ -291,8 +289,8 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) vers = (desc->v2.Hdr & 0x0000ff00) >> 8; switch (vers) { - case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, &fw); break; - case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, &fw); break; + case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, fw); break; + case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, fw); break; default: nvkm_error(subdev, "%s(v%d): version unknown\n", name, vers); return -EINVAL; @@ -303,15 +301,19 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) return ret; } - /* Boot. */ - ret = nvkm_falcon_fw_boot(&fw, subdev, true, &mbox0, NULL, 0, 0); - nvkm_falcon_fw_dtor(&fw); - if (ret) - return ret; - return 0; } +static int +nvkm_gsp_fwsec_boot(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw) +{ + struct nvkm_subdev *subdev = &gsp->subdev; + u32 mbox0 = 0; + + /* Boot */ + return nvkm_falcon_fw_boot(fw, subdev, true, &mbox0, NULL, 0, 0); +} + int nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) { @@ -320,7 +322,7 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) int ret; u32 err; - ret = nvkm_gsp_fwsec(gsp, "fwsec-sb", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); + ret = nvkm_gsp_fwsec_boot(gsp, &gsp->fws.falcon.sb); if (ret) return ret; @@ -335,26 +337,47 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) } int +nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + return nvkm_gsp_fwsec_init(gsp, &gsp->fws.falcon.sb, "fwsec-sb", + NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); +} + +void +nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); +} + +int nvkm_gsp_fwsec_frts(struct nvkm_gsp *gsp) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; + struct nvkm_falcon_fw fw = {}; int ret; u32 err, wpr2_lo, wpr2_hi; - ret = nvkm_gsp_fwsec(gsp, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); + ret = nvkm_gsp_fwsec_init(gsp, &fw, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); if (ret) return ret; + ret = nvkm_gsp_fwsec_boot(gsp, &fw); + if (ret) + goto fwsec_dtor; + /* Verify. */ err = nvkm_rd32(device, 0x001400 + (0xe * 4)) >> 16; if (err) { nvkm_error(subdev, "fwsec-frts: 0x%04x\n", err); - return -EIO; + ret = -EIO; + } else { + wpr2_lo = nvkm_rd32(device, 0x1fa824); + wpr2_hi = nvkm_rd32(device, 0x1fa828); + nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); } - wpr2_lo = nvkm_rd32(device, 0x1fa824); - wpr2_hi = nvkm_rd32(device, 0x1fa828); - nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); - return 0; +fwsec_dtor: + nvkm_falcon_fw_dtor(&fw); + return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h index c3494b7ac572..86bdd203bc10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h @@ -6,7 +6,10 @@ enum nvkm_acr_lsf_id; int nvkm_gsp_fwsec_frts(struct nvkm_gsp *); + +int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *); int nvkm_gsp_fwsec_sb(struct nvkm_gsp *); +void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *); struct nvkm_gsp_fwif { int version; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c index 32e6a065d6d7..2a7e80c6d70f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c @@ -1817,12 +1817,16 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) RM_RISCV_UCODE_DESC *desc; int ret; + ret = nvkm_gsp_fwsec_sb_ctor(gsp); + if (ret) + return ret; + hdr = nvfw_bin_hdr(&gsp->subdev, fw->data); desc = (void *)fw->data + hdr->header_offset; ret = nvkm_gsp_mem_ctor(gsp, hdr->data_size, &gsp->boot.fw); if (ret) - return ret; + goto dtor_fwsec; memcpy(gsp->boot.fw.data, fw->data + hdr->data_offset, hdr->data_size); @@ -1831,6 +1835,9 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) gsp->boot.manifest_offset = desc->manifestOffset; gsp->boot.app_version = desc->appVersion; return 0; +dtor_fwsec: + nvkm_gsp_fwsec_sb_dtor(gsp); + return ret; } static const struct nvkm_firmware_func @@ -2101,6 +2108,7 @@ r535_gsp_dtor(struct nvkm_gsp *gsp) mutex_destroy(&gsp->cmdq.mutex); nvkm_gsp_dtor_fws(gsp); + nvkm_gsp_fwsec_sb_dtor(gsp); nvkm_gsp_mem_dtor(&gsp->rmargs); nvkm_gsp_mem_dtor(&gsp->wpr_meta); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c index 561e6643dcbb..6e5173f98a22 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c @@ -213,7 +213,7 @@ static const struct backlight_properties nt35560_bl_props = { static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) { - struct device dev = dsi_ctx->dsi->dev; + struct device *dev = &dsi_ctx->dsi->dev; u8 vendor, version, panel; u16 val; @@ -225,7 +225,7 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) return; if (vendor == 0x00) { - dev_err(&dev, "device vendor ID is zero\n"); + dev_err(dev, "device vendor ID is zero\n"); dsi_ctx->accum_err = -ENODEV; return; } @@ -236,12 +236,12 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) case DISPLAY_SONY_ACX424AKP_ID2: case DISPLAY_SONY_ACX424AKP_ID3: case DISPLAY_SONY_ACX424AKP_ID4: - dev_info(&dev, + dev_info(dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; default: - dev_info(&dev, + dev_info(dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index b834123a6560..a6b8024e1a3c 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -779,6 +779,12 @@ struct panthor_job_profiling_data { */ #define MAX_GROUPS_PER_POOL 128 +/* + * Mark added on an entry of group pool Xarray to identify if the group has + * been fully initialized and can be accessed elsewhere in the driver code. + */ +#define GROUP_REGISTERED XA_MARK_1 + /** * struct panthor_group_pool - Group pool * @@ -3007,7 +3013,7 @@ void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile) return; xa_lock(&gpool->xa); - xa_for_each(&gpool->xa, i, group) { + xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) { guard(spinlock)(&group->fdinfo.lock); pfile->stats.cycles += group->fdinfo.data.cycles; pfile->stats.time += group->fdinfo.data.time; @@ -3727,6 +3733,8 @@ int panthor_group_create(struct panthor_file *pfile, group_init_task_info(group); + xa_set_mark(&gpool->xa, gid, GROUP_REGISTERED); + return gid; err_erase_gid: @@ -3744,6 +3752,9 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) struct panthor_scheduler *sched = ptdev->scheduler; struct panthor_group *group; + if (!xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED)) + return -EINVAL; + group = xa_erase(&gpool->xa, group_handle); if (!group) return -EINVAL; @@ -3769,12 +3780,12 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) } static struct panthor_group *group_from_handle(struct panthor_group_pool *pool, - u32 group_handle) + unsigned long group_handle) { struct panthor_group *group; xa_lock(&pool->xa); - group = group_get(xa_load(&pool->xa, group_handle)); + group = group_get(xa_find(&pool->xa, &group_handle, group_handle, GROUP_REGISTERED)); xa_unlock(&pool->xa); return group; @@ -3861,7 +3872,7 @@ panthor_fdinfo_gather_group_mem_info(struct panthor_file *pfile, return; xa_lock(&gpool->xa); - xa_for_each(&gpool->xa, i, group) { + xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) { stats->resident += group->fdinfo.kbo_sizes; if (group->csg_id >= 0) stats->active += group->fdinfo.kbo_sizes; diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c index 9413b76d0bfc..4ef2e3c129ed 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c @@ -492,9 +492,9 @@ static void rcar_mipi_dsi_set_display_timing(struct rcar_mipi_dsi *dsi, /* Configuration for Video Parameters, input is always RGB888 */ vprmset0r = TXVMVPRMSET0R_BPP_24; - if (mode->flags & DRM_MODE_FLAG_NVSYNC) + if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) vprmset0r |= TXVMVPRMSET0R_VSPOL_LOW; - if (mode->flags & DRM_MODE_FLAG_NHSYNC) + if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) vprmset0r |= TXVMVPRMSET0R_HSPOL_LOW; vprmset1r = TXVMVPRMSET1R_VACTIVE(mode->vdisplay) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 5718d9d83a49..52c95131af5a 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -586,7 +586,7 @@ out: drm_modeset_unlock(&crtc->mutex); } -static void tilcdc_crtc_destroy(struct drm_crtc *crtc) +void tilcdc_crtc_destroy(struct drm_crtc *crtc) { struct tilcdc_drm_private *priv = crtc->dev->dev_private; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 7caec4d38ddf..3dcbec312bac 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -172,8 +172,7 @@ static void tilcdc_fini(struct drm_device *dev) if (priv->crtc) tilcdc_crtc_shutdown(priv->crtc); - if (priv->is_registered) - drm_dev_unregister(dev); + drm_dev_unregister(dev); drm_kms_helper_poll_fini(dev); drm_atomic_helper_shutdown(dev); @@ -220,21 +219,21 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) priv->wq = alloc_ordered_workqueue("tilcdc", 0); if (!priv->wq) { ret = -ENOMEM; - goto init_failed; + goto put_drm; } priv->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->mmio)) { dev_err(dev, "failed to request / ioremap\n"); ret = PTR_ERR(priv->mmio); - goto init_failed; + goto free_wq; } priv->clk = clk_get(dev, "fck"); if (IS_ERR(priv->clk)) { dev_err(dev, "failed to get functional clock\n"); ret = -ENODEV; - goto init_failed; + goto free_wq; } pm_runtime_enable(dev); @@ -313,7 +312,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = tilcdc_crtc_create(ddev); if (ret < 0) { dev_err(dev, "failed to create crtc\n"); - goto init_failed; + goto disable_pm; } modeset_init(ddev); @@ -324,46 +323,46 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) if (ret) { dev_err(dev, "failed to register cpufreq notifier\n"); priv->freq_transition.notifier_call = NULL; - goto init_failed; + goto destroy_crtc; } #endif if (priv->is_componentized) { ret = component_bind_all(dev, ddev); if (ret < 0) - goto init_failed; + goto unregister_cpufreq_notif; ret = tilcdc_add_component_encoder(ddev); if (ret < 0) - goto init_failed; + goto unbind_component; } else { ret = tilcdc_attach_external_device(ddev); if (ret) - goto init_failed; + goto unregister_cpufreq_notif; } if (!priv->external_connector && ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { dev_err(dev, "no encoders/connectors found\n"); ret = -EPROBE_DEFER; - goto init_failed; + goto unbind_component; } ret = drm_vblank_init(ddev, 1); if (ret < 0) { dev_err(dev, "failed to initialize vblank\n"); - goto init_failed; + goto unbind_component; } ret = platform_get_irq(pdev, 0); if (ret < 0) - goto init_failed; + goto unbind_component; priv->irq = ret; ret = tilcdc_irq_install(ddev, priv->irq); if (ret < 0) { dev_err(dev, "failed to install IRQ handler\n"); - goto init_failed; + goto unbind_component; } drm_mode_config_reset(ddev); @@ -372,16 +371,34 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = drm_dev_register(ddev, 0); if (ret) - goto init_failed; - priv->is_registered = true; + goto stop_poll; drm_client_setup_with_color_mode(ddev, bpp); return 0; -init_failed: - tilcdc_fini(ddev); +stop_poll: + drm_kms_helper_poll_fini(ddev); + tilcdc_irq_uninstall(ddev); +unbind_component: + if (priv->is_componentized) + component_unbind_all(dev, ddev); +unregister_cpufreq_notif: +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&priv->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +destroy_crtc: +#endif + tilcdc_crtc_destroy(priv->crtc); +disable_pm: + pm_runtime_disable(dev); + clk_put(priv->clk); +free_wq: + destroy_workqueue(priv->wq); +put_drm: platform_set_drvdata(pdev, NULL); + ddev->dev_private = NULL; + drm_dev_put(ddev); return ret; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index b818448c83f6..58b276f82a66 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -82,7 +82,6 @@ struct tilcdc_drm_private { struct drm_encoder *external_encoder; struct drm_connector *external_connector; - bool is_registered; bool is_componentized; bool irq_enabled; }; @@ -164,6 +163,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc, void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, bool simulate_vesa_sync); void tilcdc_crtc_shutdown(struct drm_crtc *crtc); +void tilcdc_crtc_destroy(struct drm_crtc *crtc); int tilcdc_crtc_update_fb(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index b47020fca199..e6abc7b40b18 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -434,6 +434,11 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, if (ret) return ret; + if (!bo->resource) { + ret = -ENODATA; + goto unlock; + } + switch (bo->resource->mem_type) { case TTM_PL_SYSTEM: fallthrough; @@ -448,6 +453,7 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, ret = -EIO; } +unlock: ttm_bo_unreserve(bo); return ret; diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index a444d41e53b6..472bca54642b 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -27,6 +27,7 @@ #include <linux/hid.h> #include <linux/module.h> #include <linux/platform_data/x86/asus-wmi.h> +#include <linux/platform_data/x86/asus-wmi-leds-ids.h> #include <linux/input/mt.h> #include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */ #include <linux/power_supply.h> diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 0b8c391a0342..7937ac0cbd0f 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -17,7 +17,8 @@ config HYPERV config HYPERV_VTL_MODE bool "Enable Linux to boot in VTL context" - depends on (X86_64 || ARM64) && HYPERV + depends on (X86_64 && HAVE_STATIC_CALL) || ARM64 + depends on HYPERV depends on SMP default n help @@ -75,6 +76,8 @@ config MSHV_ROOT depends on PAGE_SIZE_4KB select EVENTFD select VIRT_XFER_TO_GUEST_WORK + select HMM_MIRROR + select MMU_NOTIFIER default n help Select this option to enable support for booting and running as root @@ -82,4 +85,28 @@ config MSHV_ROOT If unsure, say N. +config MSHV_VTL + tristate "Microsoft Hyper-V VTL driver" + depends on X86_64 && HYPERV_VTL_MODE + depends on HYPERV_VMBUS + # Mapping VTL0 memory to a userspace process in VTL2 is supported in OpenHCL. + # VTL2 for OpenHCL makes use of Huge Pages to improve performance on VMs, + # specially with large memory requirements. + depends on TRANSPARENT_HUGEPAGE + # MTRRs are controlled by VTL0, and are not specific to individual VTLs. + # Therefore, do not attempt to access or modify MTRRs here. + depends on !MTRR + select CPUMASK_OFFSTACK + select VIRT_XFER_TO_GUEST_WORK + default n + help + Select this option to enable Hyper-V VTL driver support. + This driver provides interfaces for Virtual Machine Manager (VMM) running in VTL2 + userspace to create VTLs and partitions, setup and manage VTL0 memory and + allow userspace to make direct hypercalls. This also allows to map VTL0's address + space to a usermode process in VTL2 and supports getting new VMBus messages and channel + events in VTL2. + + If unsure, say N. + endmenu diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile index 1a1677bf4dac..a49f93c2d245 100644 --- a/drivers/hv/Makefile +++ b/drivers/hv/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_HYPERV_VMBUS) += hv_vmbus.o obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o obj-$(CONFIG_MSHV_ROOT) += mshv_root.o +obj-$(CONFIG_MSHV_VTL) += mshv_vtl.o CFLAGS_hv_trace.o = -I$(src) CFLAGS_hv_balloon.o = -I$(src) @@ -13,8 +14,12 @@ hv_vmbus-y := vmbus_drv.o \ hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o mshv_root-y := mshv_root_main.o mshv_synic.o mshv_eventfd.o mshv_irq.o \ - mshv_root_hv_call.o mshv_portid_table.o + mshv_root_hv_call.o mshv_portid_table.o mshv_regions.o +mshv_vtl-y := mshv_vtl_main.o # Code that must be built-in obj-$(CONFIG_HYPERV) += hv_common.o -obj-$(subst m,y,$(CONFIG_MSHV_ROOT)) += hv_proc.o mshv_common.o +obj-$(subst m,y,$(CONFIG_MSHV_ROOT)) += hv_proc.o +ifneq ($(CONFIG_MSHV_ROOT)$(CONFIG_MSHV_VTL),) + obj-y += mshv_common.o +endif diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 162d6aeece7b..6821f225248b 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -410,6 +410,21 @@ static int create_gpadl_header(enum hv_gpadl_type type, void *kbuffer, return 0; } +static void vmbus_free_channel_msginfo(struct vmbus_channel_msginfo *msginfo) +{ + struct vmbus_channel_msginfo *submsginfo, *tmp; + + if (!msginfo) + return; + + list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist, + msglistentry) { + kfree(submsginfo); + } + + kfree(msginfo); +} + /* * __vmbus_establish_gpadl - Establish a GPADL for a buffer or ringbuffer * @@ -429,7 +444,7 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, struct vmbus_channel_gpadl_header *gpadlmsg; struct vmbus_channel_gpadl_body *gpadl_body; struct vmbus_channel_msginfo *msginfo = NULL; - struct vmbus_channel_msginfo *submsginfo, *tmp; + struct vmbus_channel_msginfo *submsginfo; struct list_head *curr; u32 next_gpadl_handle; unsigned long flags; @@ -444,20 +459,24 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, return ret; } - /* - * Set the "decrypted" flag to true for the set_memory_decrypted() - * success case. In the failure case, the encryption state of the - * memory is unknown. Leave "decrypted" as true to ensure the - * memory will be leaked instead of going back on the free list. - */ - gpadl->decrypted = true; - ret = set_memory_decrypted((unsigned long)kbuffer, - PFN_UP(size)); - if (ret) { - dev_warn(&channel->device_obj->device, - "Failed to set host visibility for new GPADL %d.\n", - ret); - return ret; + gpadl->decrypted = !((channel->co_external_memory && type == HV_GPADL_BUFFER) || + (channel->co_ring_buffer && type == HV_GPADL_RING)); + if (gpadl->decrypted) { + /* + * The "decrypted" flag being true assumes that set_memory_decrypted() succeeds. + * But if it fails, the encryption state of the memory is unknown. In that case, + * leave "decrypted" as true to ensure the memory is leaked instead of going back + * on the free list. + */ + ret = set_memory_decrypted((unsigned long)kbuffer, + PFN_UP(size)); + if (ret) { + dev_warn(&channel->device_obj->device, + "Failed to set host visibility for new GPADL %d.\n", + ret); + vmbus_free_channel_msginfo(msginfo); + return ret; + } } init_completion(&msginfo->waitevent); @@ -532,12 +551,8 @@ cleanup: spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&msginfo->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); - list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist, - msglistentry) { - kfree(submsginfo); - } - kfree(msginfo); + vmbus_free_channel_msginfo(msginfo); if (ret) { /* @@ -545,8 +560,10 @@ cleanup: * left as true so the memory is leaked instead of being * put back on the free list. */ - if (!set_memory_encrypted((unsigned long)kbuffer, PFN_UP(size))) - gpadl->decrypted = false; + if (gpadl->decrypted) { + if (!set_memory_encrypted((unsigned long)kbuffer, PFN_UP(size))) + gpadl->decrypted = false; + } } return ret; @@ -573,7 +590,7 @@ EXPORT_SYMBOL_GPL(vmbus_establish_gpadl); * keeps track of the next available slot in the array. Initially, each * slot points to the next one (as in a Linked List). The last slot * does not point to anything, so its value is U64_MAX by default. - * @size The size of the array + * @size: The size of the array */ static u64 *request_arr_init(u32 size) { @@ -677,12 +694,13 @@ static int __vmbus_open(struct vmbus_channel *newchannel, goto error_clean_ring; err = hv_ringbuffer_init(&newchannel->outbound, - page, send_pages, 0); + page, send_pages, 0, newchannel->co_ring_buffer); if (err) goto error_free_gpadl; err = hv_ringbuffer_init(&newchannel->inbound, &page[send_pages], - recv_pages, newchannel->max_pkt_size); + recv_pages, newchannel->max_pkt_size, + newchannel->co_ring_buffer); if (err) goto error_free_gpadl; @@ -863,8 +881,11 @@ post_msg_err: kfree(info); - ret = set_memory_encrypted((unsigned long)gpadl->buffer, - PFN_UP(gpadl->size)); + if (gpadl->decrypted) + ret = set_memory_encrypted((unsigned long)gpadl->buffer, + PFN_UP(gpadl->size)); + else + ret = 0; if (ret) pr_warn("Fail to set mem host visibility in GPADL teardown %d.\n", ret); diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 65dd299e2944..74fed2c073d4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -844,14 +844,14 @@ static void vmbus_wait_for_unload(void) = per_cpu_ptr(hv_context.cpu_context, cpu); /* - * In a CoCo VM the synic_message_page is not allocated + * In a CoCo VM the hyp_synic_message_page is not allocated * in hv_synic_alloc(). Instead it is set/cleared in - * hv_synic_enable_regs() and hv_synic_disable_regs() + * hv_hyp_synic_enable_regs() and hv_hyp_synic_disable_regs() * such that it is set only when the CPU is online. If * not all present CPUs are online, the message page * might be NULL, so skip such CPUs. */ - page_addr = hv_cpu->synic_message_page; + page_addr = hv_cpu->hyp_synic_message_page; if (!page_addr) continue; @@ -892,7 +892,7 @@ completed: struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); - page_addr = hv_cpu->synic_message_page; + page_addr = hv_cpu->hyp_synic_message_page; if (!page_addr) continue; @@ -1022,6 +1022,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) struct vmbus_channel_offer_channel *offer; struct vmbus_channel *oldchannel, *newchannel; size_t offer_sz; + bool co_ring_buffer, co_external_memory; offer = (struct vmbus_channel_offer_channel *)hdr; @@ -1034,6 +1035,22 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) return; } + co_ring_buffer = is_co_ring_buffer(offer); + co_external_memory = is_co_external_memory(offer); + if (!co_ring_buffer && co_external_memory) { + pr_err("Invalid offer relid=%d: the ring buffer isn't encrypted\n", + offer->child_relid); + return; + } + if (co_ring_buffer || co_external_memory) { + if (vmbus_proto_version < VERSION_WIN10_V6_0 || !vmbus_is_confidential()) { + pr_err("Invalid offer relid=%d: no support for confidential VMBus\n", + offer->child_relid); + atomic_dec(&vmbus_connection.offer_in_progress); + return; + } + } + oldchannel = find_primary_channel_by_offer(offer); if (oldchannel != NULL) { @@ -1112,6 +1129,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) pr_err("Unable to allocate channel object\n"); return; } + newchannel->co_ring_buffer = co_ring_buffer; + newchannel->co_external_memory = co_external_memory; vmbus_setup_channel_state(newchannel, offer); diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 1fe3573ae52a..5d9cb5bf2d62 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -51,6 +51,7 @@ EXPORT_SYMBOL_GPL(vmbus_proto_version); * Linux guests and are not listed. */ static __u32 vmbus_versions[] = { + VERSION_WIN10_V6_0, VERSION_WIN10_V5_3, VERSION_WIN10_V5_2, VERSION_WIN10_V5_1, @@ -65,7 +66,7 @@ static __u32 vmbus_versions[] = { * Maximal VMBus protocol version guests can negotiate. Useful to cap the * VMBus version for testing and debugging purpose. */ -static uint max_version = VERSION_WIN10_V5_3; +static uint max_version = VERSION_WIN10_V6_0; module_param(max_version, uint, S_IRUGO); MODULE_PARM_DESC(max_version, @@ -105,6 +106,9 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; } + if (vmbus_is_confidential() && version >= VERSION_WIN10_V6_0) + msg->feature_flags = VMBUS_FEATURE_FLAG_CONFIDENTIAL_CHANNELS; + /* * shared_gpa_boundary is zero in non-SNP VMs, so it's safe to always * bitwise OR it diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index b14c5f9e0ef2..c100f04b3581 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -18,6 +18,7 @@ #include <linux/clockchips.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/export.h> #include <clocksource/hyperv_timer.h> #include <asm/mshyperv.h> #include <linux/set_memory.h> @@ -25,6 +26,7 @@ /* The one and only */ struct hv_context hv_context; +EXPORT_SYMBOL_FOR_MODULES(hv_context, "mshv_vtl"); /* * hv_init - Main initialization routine. @@ -74,7 +76,11 @@ int hv_post_message(union hv_connection_id connection_id, aligned_msg->payload_size = payload_size; memcpy((void *)aligned_msg->payload, payload, payload_size); - if (ms_hyperv.paravisor_present) { + if (ms_hyperv.paravisor_present && !vmbus_is_confidential()) { + /* + * If the VMBus isn't confidential, use the CoCo-specific + * mechanism to communicate with the hypervisor. + */ if (hv_isolation_type_tdx()) status = hv_tdx_hypercall(HVCALL_POST_MESSAGE, virt_to_phys(aligned_msg), 0); @@ -88,6 +94,11 @@ int hv_post_message(union hv_connection_id connection_id, u64 control = HVCALL_POST_MESSAGE; control |= hv_nested ? HV_HYPERCALL_NESTED : 0; + /* + * If there is no paravisor, this will go to the hypervisor. + * In the Confidential VMBus case, there is the paravisor + * to which this will trap. + */ status = hv_do_hypercall(control, aligned_msg, NULL); } @@ -95,11 +106,72 @@ int hv_post_message(union hv_connection_id connection_id, return hv_result(status); } +EXPORT_SYMBOL_FOR_MODULES(hv_post_message, "mshv_vtl"); + +static int hv_alloc_page(void **page, bool decrypt, const char *note) +{ + int ret = 0; + + /* + * After the page changes its encryption status, its contents might + * appear scrambled on some hardware. Thus `get_zeroed_page` would + * zero the page out in vain, so do that explicitly exactly once. + * + * By default, the page is allocated encrypted in a CoCo VM. + */ + *page = (void *)__get_free_page(GFP_KERNEL); + if (!*page) + return -ENOMEM; + + if (decrypt) + ret = set_memory_decrypted((unsigned long)*page, 1); + if (ret) + goto failed; + + memset(*page, 0, PAGE_SIZE); + return 0; + +failed: + /* + * Report the failure but don't put the page back on the free list as + * its encryption status is unknown. + */ + pr_err("allocation failed for %s page, error %d, decrypted %d\n", + note, ret, decrypt); + *page = NULL; + return ret; +} + +static int hv_free_page(void **page, bool encrypt, const char *note) +{ + int ret = 0; + + if (!*page) + return 0; + + if (encrypt) + ret = set_memory_encrypted((unsigned long)*page, 1); + + /* + * In the case of the failure, the page is leaked. Something is wrong, + * prefer to lose the page with the unknown encryption status and stay afloat. + */ + if (ret) + pr_err("deallocation failed for %s page, error %d, encrypt %d\n", + note, ret, encrypt); + else + free_page((unsigned long)*page); + + *page = NULL; + + return ret; +} int hv_synic_alloc(void) { int cpu, ret = -ENOMEM; struct hv_per_cpu_context *hv_cpu; + const bool decrypt = !vmbus_is_confidential(); /* * First, zero all per-cpu memory areas so hv_synic_free() can @@ -125,73 +197,37 @@ int hv_synic_alloc(void) vmbus_on_msg_dpc, (unsigned long)hv_cpu); if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) { - hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); - if (!hv_cpu->post_msg_page) { - pr_err("Unable to allocate post msg page\n"); + ret = hv_alloc_page(&hv_cpu->post_msg_page, + decrypt, "post msg"); + if (ret) goto err; - } - - ret = set_memory_decrypted((unsigned long)hv_cpu->post_msg_page, 1); - if (ret) { - pr_err("Failed to decrypt post msg page: %d\n", ret); - /* Just leak the page, as it's unsafe to free the page. */ - hv_cpu->post_msg_page = NULL; - goto err; - } - - memset(hv_cpu->post_msg_page, 0, PAGE_SIZE); } /* - * Synic message and event pages are allocated by paravisor. - * Skip these pages allocation here. + * If these SynIC pages are not allocated, SIEF and SIM pages + * are configured using what the root partition or the paravisor + * provides upon reading the SIEFP and SIMP registers. */ if (!ms_hyperv.paravisor_present && !hv_root_partition()) { - hv_cpu->synic_message_page = - (void *)get_zeroed_page(GFP_ATOMIC); - if (!hv_cpu->synic_message_page) { - pr_err("Unable to allocate SYNIC message page\n"); + ret = hv_alloc_page(&hv_cpu->hyp_synic_message_page, + decrypt, "hypervisor SynIC msg"); + if (ret) goto err; - } - - hv_cpu->synic_event_page = - (void *)get_zeroed_page(GFP_ATOMIC); - if (!hv_cpu->synic_event_page) { - pr_err("Unable to allocate SYNIC event page\n"); - - free_page((unsigned long)hv_cpu->synic_message_page); - hv_cpu->synic_message_page = NULL; + ret = hv_alloc_page(&hv_cpu->hyp_synic_event_page, + decrypt, "hypervisor SynIC event"); + if (ret) goto err; - } } - if (!ms_hyperv.paravisor_present && - (hv_isolation_type_snp() || hv_isolation_type_tdx())) { - ret = set_memory_decrypted((unsigned long) - hv_cpu->synic_message_page, 1); - if (ret) { - pr_err("Failed to decrypt SYNIC msg page: %d\n", ret); - hv_cpu->synic_message_page = NULL; - - /* - * Free the event page here so that hv_synic_free() - * won't later try to re-encrypt it. - */ - free_page((unsigned long)hv_cpu->synic_event_page); - hv_cpu->synic_event_page = NULL; + if (vmbus_is_confidential()) { + ret = hv_alloc_page(&hv_cpu->para_synic_message_page, + false, "paravisor SynIC msg"); + if (ret) goto err; - } - - ret = set_memory_decrypted((unsigned long) - hv_cpu->synic_event_page, 1); - if (ret) { - pr_err("Failed to decrypt SYNIC event page: %d\n", ret); - hv_cpu->synic_event_page = NULL; + ret = hv_alloc_page(&hv_cpu->para_synic_event_page, + false, "paravisor SynIC event"); + if (ret) goto err; - } - - memset(hv_cpu->synic_message_page, 0, PAGE_SIZE); - memset(hv_cpu->synic_event_page, 0, PAGE_SIZE); } } @@ -207,70 +243,46 @@ err: void hv_synic_free(void) { - int cpu, ret; + int cpu; + const bool encrypt = !vmbus_is_confidential(); for_each_present_cpu(cpu) { struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); - /* It's better to leak the page if the encryption fails. */ - if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) { - if (hv_cpu->post_msg_page) { - ret = set_memory_encrypted((unsigned long) - hv_cpu->post_msg_page, 1); - if (ret) { - pr_err("Failed to encrypt post msg page: %d\n", ret); - hv_cpu->post_msg_page = NULL; - } - } + if (ms_hyperv.paravisor_present && hv_isolation_type_tdx()) + hv_free_page(&hv_cpu->post_msg_page, + encrypt, "post msg"); + if (!ms_hyperv.paravisor_present && !hv_root_partition()) { + hv_free_page(&hv_cpu->hyp_synic_event_page, + encrypt, "hypervisor SynIC event"); + hv_free_page(&hv_cpu->hyp_synic_message_page, + encrypt, "hypervisor SynIC msg"); } - - if (!ms_hyperv.paravisor_present && - (hv_isolation_type_snp() || hv_isolation_type_tdx())) { - if (hv_cpu->synic_message_page) { - ret = set_memory_encrypted((unsigned long) - hv_cpu->synic_message_page, 1); - if (ret) { - pr_err("Failed to encrypt SYNIC msg page: %d\n", ret); - hv_cpu->synic_message_page = NULL; - } - } - - if (hv_cpu->synic_event_page) { - ret = set_memory_encrypted((unsigned long) - hv_cpu->synic_event_page, 1); - if (ret) { - pr_err("Failed to encrypt SYNIC event page: %d\n", ret); - hv_cpu->synic_event_page = NULL; - } - } + if (vmbus_is_confidential()) { + hv_free_page(&hv_cpu->para_synic_event_page, + false, "paravisor SynIC event"); + hv_free_page(&hv_cpu->para_synic_message_page, + false, "paravisor SynIC msg"); } - - free_page((unsigned long)hv_cpu->post_msg_page); - free_page((unsigned long)hv_cpu->synic_event_page); - free_page((unsigned long)hv_cpu->synic_message_page); } kfree(hv_context.hv_numa_map); } /* - * hv_synic_init - Initialize the Synthetic Interrupt Controller. - * - * If it is already initialized by another entity (ie x2v shim), we need to - * retrieve the initialized message and event pages. Otherwise, we create and - * initialize the message and event pages. + * hv_hyp_synic_enable_regs - Initialize the Synthetic Interrupt Controller + * with the hypervisor. */ -void hv_synic_enable_regs(unsigned int cpu) +void hv_hyp_synic_enable_regs(unsigned int cpu) { struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); union hv_synic_simp simp; union hv_synic_siefp siefp; union hv_synic_sint shared_sint; - union hv_synic_scontrol sctrl; - /* Setup the Synic's message page */ + /* Setup the Synic's message page with the hypervisor. */ simp.as_uint64 = hv_get_msr(HV_MSR_SIMP); simp.simp_enabled = 1; @@ -278,18 +290,18 @@ void hv_synic_enable_regs(unsigned int cpu) /* Mask out vTOM bit. ioremap_cache() maps decrypted */ u64 base = (simp.base_simp_gpa << HV_HYP_PAGE_SHIFT) & ~ms_hyperv.shared_gpa_boundary; - hv_cpu->synic_message_page = + hv_cpu->hyp_synic_message_page = (void *)ioremap_cache(base, HV_HYP_PAGE_SIZE); - if (!hv_cpu->synic_message_page) + if (!hv_cpu->hyp_synic_message_page) pr_err("Fail to map synic message page.\n"); } else { - simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) + simp.base_simp_gpa = virt_to_phys(hv_cpu->hyp_synic_message_page) >> HV_HYP_PAGE_SHIFT; } hv_set_msr(HV_MSR_SIMP, simp.as_uint64); - /* Setup the Synic's event page */ + /* Setup the Synic's event page with the hypervisor. */ siefp.as_uint64 = hv_get_msr(HV_MSR_SIEFP); siefp.siefp_enabled = 1; @@ -297,16 +309,17 @@ void hv_synic_enable_regs(unsigned int cpu) /* Mask out vTOM bit. ioremap_cache() maps decrypted */ u64 base = (siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT) & ~ms_hyperv.shared_gpa_boundary; - hv_cpu->synic_event_page = + hv_cpu->hyp_synic_event_page = (void *)ioremap_cache(base, HV_HYP_PAGE_SIZE); - if (!hv_cpu->synic_event_page) + if (!hv_cpu->hyp_synic_event_page) pr_err("Fail to map synic event page.\n"); } else { - siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) + siefp.base_siefp_gpa = virt_to_phys(hv_cpu->hyp_synic_event_page) >> HV_HYP_PAGE_SHIFT; } hv_set_msr(HV_MSR_SIEFP, siefp.as_uint64); + hv_enable_coco_interrupt(cpu, vmbus_interrupt, true); /* Setup the shared SINT. */ if (vmbus_irq != -1) @@ -317,6 +330,11 @@ void hv_synic_enable_regs(unsigned int cpu) shared_sint.masked = false; shared_sint.auto_eoi = hv_recommend_using_aeoi(); hv_set_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); +} + +static void hv_hyp_synic_enable_interrupts(void) +{ + union hv_synic_scontrol sctrl; /* Enable the global synic bit */ sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL); @@ -325,23 +343,72 @@ void hv_synic_enable_regs(unsigned int cpu) hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64); } +static void hv_para_synic_enable_regs(unsigned int cpu) +{ + union hv_synic_simp simp; + union hv_synic_siefp siefp; + struct hv_per_cpu_context *hv_cpu + = per_cpu_ptr(hv_context.cpu_context, cpu); + + /* Setup the Synic's message page with the paravisor. */ + simp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIMP); + simp.simp_enabled = 1; + simp.base_simp_gpa = virt_to_phys(hv_cpu->para_synic_message_page) + >> HV_HYP_PAGE_SHIFT; + hv_para_set_synic_register(HV_MSR_SIMP, simp.as_uint64); + + /* Setup the Synic's event page with the paravisor. */ + siefp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIEFP); + siefp.siefp_enabled = 1; + siefp.base_siefp_gpa = virt_to_phys(hv_cpu->para_synic_event_page) + >> HV_HYP_PAGE_SHIFT; + hv_para_set_synic_register(HV_MSR_SIEFP, siefp.as_uint64); +} + +static void hv_para_synic_enable_interrupts(void) +{ + union hv_synic_scontrol sctrl; + + /* Enable the global synic bit */ + sctrl.as_uint64 = hv_para_get_synic_register(HV_MSR_SCONTROL); + sctrl.enable = 1; + hv_para_set_synic_register(HV_MSR_SCONTROL, sctrl.as_uint64); +} + int hv_synic_init(unsigned int cpu) { - hv_synic_enable_regs(cpu); + if (vmbus_is_confidential()) + hv_para_synic_enable_regs(cpu); + + /* + * The SINT is set in hv_hyp_synic_enable_regs() by calling + * hv_set_msr(). hv_set_msr() in turn has special case code for the + * SINT MSRs that write to the hypervisor version of the MSR *and* + * the paravisor version of the MSR (but *without* the proxy bit when + * VMBus is confidential). + * + * Then enable interrupts via the paravisor if VMBus is confidential, + * and otherwise via the hypervisor. + */ + + hv_hyp_synic_enable_regs(cpu); + if (vmbus_is_confidential()) + hv_para_synic_enable_interrupts(); + else + hv_hyp_synic_enable_interrupts(); hv_stimer_legacy_init(cpu, VMBUS_MESSAGE_SINT); return 0; } -void hv_synic_disable_regs(unsigned int cpu) +void hv_hyp_synic_disable_regs(unsigned int cpu) { struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); union hv_synic_sint shared_sint; union hv_synic_simp simp; union hv_synic_siefp siefp; - union hv_synic_scontrol sctrl; shared_sint.as_uint64 = hv_get_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT); @@ -350,18 +417,21 @@ void hv_synic_disable_regs(unsigned int cpu) /* Need to correctly cleanup in the case of SMP!!! */ /* Disable the interrupt */ hv_set_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); + hv_enable_coco_interrupt(cpu, vmbus_interrupt, false); simp.as_uint64 = hv_get_msr(HV_MSR_SIMP); /* - * In Isolation VM, sim and sief pages are allocated by + * In Isolation VM, simp and sief pages are allocated by * paravisor. These pages also will be used by kdump * kernel. So just reset enable bit here and keep page * addresses. */ simp.simp_enabled = 0; if (ms_hyperv.paravisor_present || hv_root_partition()) { - iounmap(hv_cpu->synic_message_page); - hv_cpu->synic_message_page = NULL; + if (hv_cpu->hyp_synic_message_page) { + iounmap(hv_cpu->hyp_synic_message_page); + hv_cpu->hyp_synic_message_page = NULL; + } } else { simp.base_simp_gpa = 0; } @@ -372,21 +442,51 @@ void hv_synic_disable_regs(unsigned int cpu) siefp.siefp_enabled = 0; if (ms_hyperv.paravisor_present || hv_root_partition()) { - iounmap(hv_cpu->synic_event_page); - hv_cpu->synic_event_page = NULL; + if (hv_cpu->hyp_synic_event_page) { + iounmap(hv_cpu->hyp_synic_event_page); + hv_cpu->hyp_synic_event_page = NULL; + } } else { siefp.base_siefp_gpa = 0; } hv_set_msr(HV_MSR_SIEFP, siefp.as_uint64); +} + +static void hv_hyp_synic_disable_interrupts(void) +{ + union hv_synic_scontrol sctrl; /* Disable the global synic bit */ sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL); sctrl.enable = 0; hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64); +} - if (vmbus_irq != -1) - disable_percpu_irq(vmbus_irq); +static void hv_para_synic_disable_regs(unsigned int cpu) +{ + union hv_synic_simp simp; + union hv_synic_siefp siefp; + + /* Disable SynIC's message page in the paravisor. */ + simp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIMP); + simp.simp_enabled = 0; + hv_para_set_synic_register(HV_MSR_SIMP, simp.as_uint64); + + /* Disable SynIC's event page in the paravisor. */ + siefp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIEFP); + siefp.siefp_enabled = 0; + hv_para_set_synic_register(HV_MSR_SIEFP, siefp.as_uint64); +} + +static void hv_para_synic_disable_interrupts(void) +{ + union hv_synic_scontrol sctrl; + + /* Disable the global synic bit */ + sctrl.as_uint64 = hv_para_get_synic_register(HV_MSR_SCONTROL); + sctrl.enable = 0; + hv_para_set_synic_register(HV_MSR_SCONTROL, sctrl.as_uint64); } #define HV_MAX_TRIES 3 @@ -399,16 +499,18 @@ void hv_synic_disable_regs(unsigned int cpu) * that the normal interrupt handling mechanism will find and process the channel interrupt * "very soon", and in the process clear the bit. */ -static bool hv_synic_event_pending(void) +static bool __hv_synic_event_pending(union hv_synic_event_flags *event, int sint) { - struct hv_per_cpu_context *hv_cpu = this_cpu_ptr(hv_context.cpu_context); - union hv_synic_event_flags *event = - (union hv_synic_event_flags *)hv_cpu->synic_event_page + VMBUS_MESSAGE_SINT; - unsigned long *recv_int_page = event->flags; /* assumes VMBus version >= VERSION_WIN8 */ + unsigned long *recv_int_page; bool pending; u32 relid; int tries = 0; + if (!event) + return false; + + event += sint; + recv_int_page = event->flags; /* assumes VMBus version >= VERSION_WIN8 */ retry: pending = false; for_each_set_bit(relid, recv_int_page, HV_EVENT_FLAGS_COUNT) { @@ -425,6 +527,17 @@ retry: return pending; } +static bool hv_synic_event_pending(void) +{ + struct hv_per_cpu_context *hv_cpu = this_cpu_ptr(hv_context.cpu_context); + union hv_synic_event_flags *hyp_synic_event_page = hv_cpu->hyp_synic_event_page; + union hv_synic_event_flags *para_synic_event_page = hv_cpu->para_synic_event_page; + + return + __hv_synic_event_pending(hyp_synic_event_page, VMBUS_MESSAGE_SINT) || + __hv_synic_event_pending(para_synic_event_page, VMBUS_MESSAGE_SINT); +} + static int hv_pick_new_cpu(struct vmbus_channel *channel) { int ret = -EBUSY; @@ -517,7 +630,27 @@ int hv_synic_cleanup(unsigned int cpu) always_cleanup: hv_stimer_legacy_cleanup(cpu); - hv_synic_disable_regs(cpu); + /* + * First, disable the event and message pages + * used for communicating with the host, and then + * disable the host interrupts if VMBus is not + * confidential. + */ + hv_hyp_synic_disable_regs(cpu); + if (!vmbus_is_confidential()) + hv_hyp_synic_disable_interrupts(); + + /* + * Perform the same steps for the Confidential VMBus. + * The sequencing provides the guarantee that no data + * may be posted for processing before disabling interrupts. + */ + if (vmbus_is_confidential()) { + hv_para_synic_disable_regs(cpu); + hv_para_synic_disable_interrupts(); + } + if (vmbus_irq != -1) + disable_percpu_irq(vmbus_irq); return ret; } diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index e109a620c83f..0a3ab7efed46 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -315,9 +315,9 @@ int __init hv_common_init(void) int i; union hv_hypervisor_version_info version; - /* Get information about the Hyper-V host version */ + /* Get information about the Microsoft Hypervisor version */ if (!hv_get_hypervisor_version(&version)) - pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n", + pr_info("Hyper-V: Hypervisor Build %d.%d.%d.%d-%d-%d\n", version.major_version, version.minor_version, version.build_number, version.service_number, version.service_pack, version.service_branch); @@ -487,7 +487,7 @@ int hv_common_cpu_init(unsigned int cpu) * online and then taken offline */ if (!*inputarg) { - mem = kmalloc(pgcount * HV_HYP_PAGE_SIZE, flags); + mem = kmalloc_array(pgcount, HV_HYP_PAGE_SIZE, flags); if (!mem) return -ENOMEM; @@ -716,6 +716,27 @@ u64 __weak hv_tdx_hypercall(u64 control, u64 param1, u64 param2) } EXPORT_SYMBOL_GPL(hv_tdx_hypercall); +void __weak hv_enable_coco_interrupt(unsigned int cpu, unsigned int vector, bool set) +{ +} +EXPORT_SYMBOL_GPL(hv_enable_coco_interrupt); + +void __weak hv_para_set_sint_proxy(bool enable) +{ +} +EXPORT_SYMBOL_GPL(hv_para_set_sint_proxy); + +u64 __weak hv_para_get_synic_register(unsigned int reg) +{ + return ~0ULL; +} +EXPORT_SYMBOL_GPL(hv_para_get_synic_register); + +void __weak hv_para_set_synic_register(unsigned int reg, u64 val) +{ +} +EXPORT_SYMBOL_GPL(hv_para_set_synic_register); + void hv_identify_partition_type(void) { /* Assume guest role */ diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 36ee89c0358b..7e9c8e169c66 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -586,7 +586,7 @@ static int util_probe(struct hv_device *dev, (struct hv_util_service *)dev_id->driver_data; int ret; - srv->recv_buffer = kmalloc(HV_HYP_PAGE_SIZE * 4, GFP_KERNEL); + srv->recv_buffer = kmalloc_array(4, HV_HYP_PAGE_SIZE, GFP_KERNEL); if (!srv->recv_buffer) return -ENOMEM; srv->channel = dev->channel; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 0b450e53161e..b2862e0a317a 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -15,6 +15,7 @@ #include <linux/list.h> #include <linux/bitops.h> #include <asm/sync_bitops.h> +#include <asm/mshyperv.h> #include <linux/atomic.h> #include <linux/hyperv.h> #include <linux/interrupt.h> @@ -32,6 +33,7 @@ */ #define HV_UTIL_NEGO_TIMEOUT 55 +void vmbus_isr(void); /* Definitions for the monitored notification facility */ union hv_monitor_trigger_group { @@ -120,8 +122,26 @@ enum { * Per cpu state for channel handling */ struct hv_per_cpu_context { - void *synic_message_page; - void *synic_event_page; + /* + * SynIC pages for communicating with the host. + * + * These pages are accessible to the host partition and the hypervisor. + * They may be used for exchanging data with the host partition and the + * hypervisor even when they aren't trusted yet the guest partition + * must be prepared to handle the malicious behavior. + */ + void *hyp_synic_message_page; + void *hyp_synic_event_page; + /* + * SynIC pages for communicating with the paravisor. + * + * These pages may be accessed from within the guest partition only in + * CoCo VMs. Neither the host partition nor the hypervisor can access + * these pages in that case; they are used for exchanging data with the + * paravisor. + */ + void *para_synic_message_page; + void *para_synic_event_page; /* * The page is only used in hv_post_message() for a TDX VM (with the @@ -171,10 +191,10 @@ extern int hv_synic_alloc(void); extern void hv_synic_free(void); -extern void hv_synic_enable_regs(unsigned int cpu); +extern void hv_hyp_synic_enable_regs(unsigned int cpu); extern int hv_synic_init(unsigned int cpu); -extern void hv_synic_disable_regs(unsigned int cpu); +extern void hv_hyp_synic_disable_regs(unsigned int cpu); extern int hv_synic_cleanup(unsigned int cpu); /* Interface */ @@ -182,7 +202,8 @@ extern int hv_synic_cleanup(unsigned int cpu); void hv_ringbuffer_pre_init(struct vmbus_channel *channel); int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, - struct page *pages, u32 pagecnt, u32 max_pkt_size); + struct page *pages, u32 pagecnt, u32 max_pkt_size, + bool confidential); void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); @@ -333,6 +354,51 @@ extern const struct vmbus_channel_message_table_entry /* General vmbus interface */ +bool vmbus_is_confidential(void); + +#if IS_ENABLED(CONFIG_HYPERV_VMBUS) +/* Free the message slot and signal end-of-message if required */ +static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) +{ + /* + * On crash we're reading some other CPU's message page and we need + * to be careful: this other CPU may already had cleared the header + * and the host may already had delivered some other message there. + * In case we blindly write msg->header.message_type we're going + * to lose it. We can still lose a message of the same type but + * we count on the fact that there can only be one + * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages + * on crash. + */ + if (cmpxchg(&msg->header.message_type, old_msg_type, + HVMSG_NONE) != old_msg_type) + return; + + /* + * The cmxchg() above does an implicit memory barrier to + * ensure the write to MessageType (ie set to + * HVMSG_NONE) happens before we read the + * MessagePending and EOMing. Otherwise, the EOMing + * will not deliver any more messages since there is + * no empty slot + */ + if (msg->header.message_flags.msg_pending) { + /* + * This will cause message queue rescan to + * possibly deliver another msg from the + * hypervisor + */ + if (vmbus_is_confidential()) + hv_para_set_synic_register(HV_MSR_EOM, 0); + else + hv_set_msr(HV_MSR_EOM, 0); + } +} + +extern int vmbus_interrupt; +extern int vmbus_irq; +#endif /* CONFIG_HYPERV_VMBUS */ + struct hv_device *vmbus_device_create(const guid_t *type, const guid_t *instance, struct vmbus_channel *channel); diff --git a/drivers/hv/mshv_common.c b/drivers/hv/mshv_common.c index aa2be51979fd..58027b23c206 100644 --- a/drivers/hv/mshv_common.c +++ b/drivers/hv/mshv_common.c @@ -14,6 +14,9 @@ #include <asm/mshyperv.h> #include <linux/resume_user_mode.h> #include <linux/export.h> +#include <linux/acpi.h> +#include <linux/notifier.h> +#include <linux/reboot.h> #include "mshv.h" @@ -138,3 +141,99 @@ int hv_call_get_partition_property(u64 partition_id, return 0; } EXPORT_SYMBOL_GPL(hv_call_get_partition_property); + +/* + * Corresponding sleep states have to be initialized in order for a subsequent + * HVCALL_ENTER_SLEEP_STATE call to succeed. Currently only S5 state as per + * ACPI 6.4 chapter 7.4.2 is relevant, while S1, S2 and S3 can be supported. + * + * In order to pass proper PM values to mshv, ACPI should be initialized and + * should support S5 sleep state when this method is invoked. + */ +static int hv_initialize_sleep_states(void) +{ + u64 status; + unsigned long flags; + struct hv_input_set_system_property *in; + acpi_status acpi_status; + u8 sleep_type_a, sleep_type_b; + + if (!acpi_sleep_state_supported(ACPI_STATE_S5)) { + pr_err("%s: S5 sleep state not supported.\n", __func__); + return -ENODEV; + } + + acpi_status = acpi_get_sleep_type_data(ACPI_STATE_S5, &sleep_type_a, + &sleep_type_b); + if (ACPI_FAILURE(acpi_status)) + return -ENODEV; + + local_irq_save(flags); + in = *this_cpu_ptr(hyperv_pcpu_input_arg); + memset(in, 0, sizeof(*in)); + + in->property_id = HV_SYSTEM_PROPERTY_SLEEP_STATE; + in->set_sleep_state_info.sleep_state = HV_SLEEP_STATE_S5; + in->set_sleep_state_info.pm1a_slp_typ = sleep_type_a; + in->set_sleep_state_info.pm1b_slp_typ = sleep_type_b; + + status = hv_do_hypercall(HVCALL_SET_SYSTEM_PROPERTY, in, NULL); + local_irq_restore(flags); + + if (!hv_result_success(status)) { + hv_status_err(status, "\n"); + return hv_result_to_errno(status); + } + + return 0; +} + +/* + * This notifier initializes sleep states in mshv hypervisor which will be + * used during power off. + */ +static int hv_reboot_notifier_handler(struct notifier_block *this, + unsigned long code, void *another) +{ + int ret = 0; + + if (code == SYS_HALT || code == SYS_POWER_OFF) + ret = hv_initialize_sleep_states(); + + return ret ? NOTIFY_DONE : NOTIFY_OK; +} + +static struct notifier_block hv_reboot_notifier = { + .notifier_call = hv_reboot_notifier_handler, +}; + +void hv_sleep_notifiers_register(void) +{ + int ret; + + ret = register_reboot_notifier(&hv_reboot_notifier); + if (ret) + pr_err("%s: cannot register reboot notifier %d\n", __func__, + ret); +} + +/* + * Power off the machine by entering S5 sleep state via Hyper-V hypercall. + * This call does not return if successful. + */ +void hv_machine_power_off(void) +{ + unsigned long flags; + struct hv_input_enter_sleep_state *in; + + local_irq_save(flags); + in = *this_cpu_ptr(hyperv_pcpu_input_arg); + in->sleep_state = HV_SLEEP_STATE_S5; + + (void)hv_do_hypercall(HVCALL_ENTER_SLEEP_STATE, in, NULL); + local_irq_restore(flags); + + /* should never reach here */ + BUG(); + +} diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c index 806674722868..d93a18f09c76 100644 --- a/drivers/hv/mshv_eventfd.c +++ b/drivers/hv/mshv_eventfd.c @@ -163,8 +163,10 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd) if (hv_scheduler_type != HV_SCHEDULER_TYPE_ROOT) return -EOPNOTSUPP; +#if IS_ENABLED(CONFIG_X86) if (irq->lapic_control.logical_dest_mode) return -EOPNOTSUPP; +#endif vp = partition->pt_vp_array[irq->lapic_apic_id]; @@ -196,8 +198,10 @@ static void mshv_assert_irq_slow(struct mshv_irqfd *irqfd) unsigned int seq; int idx; +#if IS_ENABLED(CONFIG_X86) WARN_ON(irqfd->irqfd_resampler && !irq->lapic_control.level_triggered); +#endif idx = srcu_read_lock(&partition->pt_irq_srcu); if (irqfd->irqfd_girq_ent.guest_irq_num) { @@ -469,6 +473,7 @@ static int mshv_irqfd_assign(struct mshv_partition *pt, init_poll_funcptr(&irqfd->irqfd_polltbl, mshv_irqfd_queue_proc); spin_lock_irq(&pt->pt_irqfds_lock); +#if IS_ENABLED(CONFIG_X86) if (args->flags & BIT(MSHV_IRQFD_BIT_RESAMPLE) && !irqfd->irqfd_lapic_irq.lapic_control.level_triggered) { /* @@ -479,6 +484,7 @@ static int mshv_irqfd_assign(struct mshv_partition *pt, ret = -EINVAL; goto fail; } +#endif ret = 0; hlist_for_each_entry(tmp, &pt->pt_irqfds_list, irqfd_hnode) { if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx) @@ -592,7 +598,7 @@ static void mshv_irqfd_release(struct mshv_partition *pt) int mshv_irqfd_wq_init(void) { - irqfd_cleanup_wq = alloc_workqueue("mshv-irqfd-cleanup", 0, 0); + irqfd_cleanup_wq = alloc_workqueue("mshv-irqfd-cleanup", WQ_PERCPU, 0); if (!irqfd_cleanup_wq) return -ENOMEM; diff --git a/drivers/hv/mshv_irq.c b/drivers/hv/mshv_irq.c index d0fb9ef734f4..798e7e1ab06e 100644 --- a/drivers/hv/mshv_irq.c +++ b/drivers/hv/mshv_irq.c @@ -119,6 +119,10 @@ void mshv_copy_girq_info(struct mshv_guest_irq_ent *ent, lirq->lapic_vector = ent->girq_irq_data & 0xFF; lirq->lapic_apic_id = (ent->girq_addr_lo >> 12) & 0xFF; lirq->lapic_control.interrupt_type = (ent->girq_irq_data & 0x700) >> 8; +#if IS_ENABLED(CONFIG_X86) lirq->lapic_control.level_triggered = (ent->girq_irq_data >> 15) & 0x1; lirq->lapic_control.logical_dest_mode = (ent->girq_addr_lo >> 2) & 0x1; +#elif IS_ENABLED(CONFIG_ARM64) + lirq->lapic_control.asserted = 1; +#endif } diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c new file mode 100644 index 000000000000..202b9d551e39 --- /dev/null +++ b/drivers/hv/mshv_regions.c @@ -0,0 +1,555 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Microsoft Corporation. + * + * Memory region management for mshv_root module. + * + * Authors: Microsoft Linux virtualization team + */ + +#include <linux/hmm.h> +#include <linux/hyperv.h> +#include <linux/kref.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> + +#include <asm/mshyperv.h> + +#include "mshv_root.h" + +#define MSHV_MAP_FAULT_IN_PAGES PTRS_PER_PMD + +/** + * mshv_region_process_chunk - Processes a contiguous chunk of memory pages + * in a region. + * @region : Pointer to the memory region structure. + * @flags : Flags to pass to the handler. + * @page_offset: Offset into the region's pages array to start processing. + * @page_count : Number of pages to process. + * @handler : Callback function to handle the chunk. + * + * This function scans the region's pages starting from @page_offset, + * checking for contiguous present pages of the same size (normal or huge). + * It invokes @handler for the chunk of contiguous pages found. Returns the + * number of pages handled, or a negative error code if the first page is + * not present or the handler fails. + * + * Note: The @handler callback must be able to handle both normal and huge + * pages. + * + * Return: Number of pages handled, or negative error code. + */ +static long mshv_region_process_chunk(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, u64 page_count, + int (*handler)(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, + u64 page_count)) +{ + u64 count, stride; + unsigned int page_order; + struct page *page; + int ret; + + page = region->pages[page_offset]; + if (!page) + return -EINVAL; + + page_order = folio_order(page_folio(page)); + /* The hypervisor only supports 4K and 2M page sizes */ + if (page_order && page_order != HPAGE_PMD_ORDER) + return -EINVAL; + + stride = 1 << page_order; + + /* Start at stride since the first page is validated */ + for (count = stride; count < page_count; count += stride) { + page = region->pages[page_offset + count]; + + /* Break if current page is not present */ + if (!page) + break; + + /* Break if page size changes */ + if (page_order != folio_order(page_folio(page))) + break; + } + + ret = handler(region, flags, page_offset, count); + if (ret) + return ret; + + return count; +} + +/** + * mshv_region_process_range - Processes a range of memory pages in a + * region. + * @region : Pointer to the memory region structure. + * @flags : Flags to pass to the handler. + * @page_offset: Offset into the region's pages array to start processing. + * @page_count : Number of pages to process. + * @handler : Callback function to handle each chunk of contiguous + * pages. + * + * Iterates over the specified range of pages in @region, skipping + * non-present pages. For each contiguous chunk of present pages, invokes + * @handler via mshv_region_process_chunk. + * + * Note: The @handler callback must be able to handle both normal and huge + * pages. + * + * Returns 0 on success, or a negative error code on failure. + */ +static int mshv_region_process_range(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, u64 page_count, + int (*handler)(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, + u64 page_count)) +{ + long ret; + + if (page_offset + page_count > region->nr_pages) + return -EINVAL; + + while (page_count) { + /* Skip non-present pages */ + if (!region->pages[page_offset]) { + page_offset++; + page_count--; + continue; + } + + ret = mshv_region_process_chunk(region, flags, + page_offset, + page_count, + handler); + if (ret < 0) + return ret; + + page_offset += ret; + page_count -= ret; + } + + return 0; +} + +struct mshv_mem_region *mshv_region_create(u64 guest_pfn, u64 nr_pages, + u64 uaddr, u32 flags) +{ + struct mshv_mem_region *region; + + region = vzalloc(sizeof(*region) + sizeof(struct page *) * nr_pages); + if (!region) + return ERR_PTR(-ENOMEM); + + region->nr_pages = nr_pages; + region->start_gfn = guest_pfn; + region->start_uaddr = uaddr; + region->hv_map_flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_ADJUSTABLE; + if (flags & BIT(MSHV_SET_MEM_BIT_WRITABLE)) + region->hv_map_flags |= HV_MAP_GPA_WRITABLE; + if (flags & BIT(MSHV_SET_MEM_BIT_EXECUTABLE)) + region->hv_map_flags |= HV_MAP_GPA_EXECUTABLE; + + kref_init(®ion->refcount); + + return region; +} + +static int mshv_region_chunk_share(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, u64 page_count) +{ + struct page *page = region->pages[page_offset]; + + if (PageHuge(page) || PageTransCompound(page)) + flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; + + return hv_call_modify_spa_host_access(region->partition->pt_id, + region->pages + page_offset, + page_count, + HV_MAP_GPA_READABLE | + HV_MAP_GPA_WRITABLE, + flags, true); +} + +int mshv_region_share(struct mshv_mem_region *region) +{ + u32 flags = HV_MODIFY_SPA_PAGE_HOST_ACCESS_MAKE_SHARED; + + return mshv_region_process_range(region, flags, + 0, region->nr_pages, + mshv_region_chunk_share); +} + +static int mshv_region_chunk_unshare(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, u64 page_count) +{ + struct page *page = region->pages[page_offset]; + + if (PageHuge(page) || PageTransCompound(page)) + flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; + + return hv_call_modify_spa_host_access(region->partition->pt_id, + region->pages + page_offset, + page_count, 0, + flags, false); +} + +int mshv_region_unshare(struct mshv_mem_region *region) +{ + u32 flags = HV_MODIFY_SPA_PAGE_HOST_ACCESS_MAKE_EXCLUSIVE; + + return mshv_region_process_range(region, flags, + 0, region->nr_pages, + mshv_region_chunk_unshare); +} + +static int mshv_region_chunk_remap(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, u64 page_count) +{ + struct page *page = region->pages[page_offset]; + + if (PageHuge(page) || PageTransCompound(page)) + flags |= HV_MAP_GPA_LARGE_PAGE; + + return hv_call_map_gpa_pages(region->partition->pt_id, + region->start_gfn + page_offset, + page_count, flags, + region->pages + page_offset); +} + +static int mshv_region_remap_pages(struct mshv_mem_region *region, + u32 map_flags, + u64 page_offset, u64 page_count) +{ + return mshv_region_process_range(region, map_flags, + page_offset, page_count, + mshv_region_chunk_remap); +} + +int mshv_region_map(struct mshv_mem_region *region) +{ + u32 map_flags = region->hv_map_flags; + + return mshv_region_remap_pages(region, map_flags, + 0, region->nr_pages); +} + +static void mshv_region_invalidate_pages(struct mshv_mem_region *region, + u64 page_offset, u64 page_count) +{ + if (region->type == MSHV_REGION_TYPE_MEM_PINNED) + unpin_user_pages(region->pages + page_offset, page_count); + + memset(region->pages + page_offset, 0, + page_count * sizeof(struct page *)); +} + +void mshv_region_invalidate(struct mshv_mem_region *region) +{ + mshv_region_invalidate_pages(region, 0, region->nr_pages); +} + +int mshv_region_pin(struct mshv_mem_region *region) +{ + u64 done_count, nr_pages; + struct page **pages; + __u64 userspace_addr; + int ret; + + for (done_count = 0; done_count < region->nr_pages; done_count += ret) { + pages = region->pages + done_count; + userspace_addr = region->start_uaddr + + done_count * HV_HYP_PAGE_SIZE; + nr_pages = min(region->nr_pages - done_count, + MSHV_PIN_PAGES_BATCH_SIZE); + + /* + * Pinning assuming 4k pages works for large pages too. + * All page structs within the large page are returned. + * + * Pin requests are batched because pin_user_pages_fast + * with the FOLL_LONGTERM flag does a large temporary + * allocation of contiguous memory. + */ + ret = pin_user_pages_fast(userspace_addr, nr_pages, + FOLL_WRITE | FOLL_LONGTERM, + pages); + if (ret < 0) + goto release_pages; + } + + return 0; + +release_pages: + mshv_region_invalidate_pages(region, 0, done_count); + return ret; +} + +static int mshv_region_chunk_unmap(struct mshv_mem_region *region, + u32 flags, + u64 page_offset, u64 page_count) +{ + struct page *page = region->pages[page_offset]; + + if (PageHuge(page) || PageTransCompound(page)) + flags |= HV_UNMAP_GPA_LARGE_PAGE; + + return hv_call_unmap_gpa_pages(region->partition->pt_id, + region->start_gfn + page_offset, + page_count, flags); +} + +static int mshv_region_unmap(struct mshv_mem_region *region) +{ + return mshv_region_process_range(region, 0, + 0, region->nr_pages, + mshv_region_chunk_unmap); +} + +static void mshv_region_destroy(struct kref *ref) +{ + struct mshv_mem_region *region = + container_of(ref, struct mshv_mem_region, refcount); + struct mshv_partition *partition = region->partition; + int ret; + + if (region->type == MSHV_REGION_TYPE_MEM_MOVABLE) + mshv_region_movable_fini(region); + + if (mshv_partition_encrypted(partition)) { + ret = mshv_region_share(region); + if (ret) { + pt_err(partition, + "Failed to regain access to memory, unpinning user pages will fail and crash the host error: %d\n", + ret); + return; + } + } + + mshv_region_unmap(region); + + mshv_region_invalidate(region); + + vfree(region); +} + +void mshv_region_put(struct mshv_mem_region *region) +{ + kref_put(®ion->refcount, mshv_region_destroy); +} + +int mshv_region_get(struct mshv_mem_region *region) +{ + return kref_get_unless_zero(®ion->refcount); +} + +/** + * mshv_region_hmm_fault_and_lock - Handle HMM faults and lock the memory region + * @region: Pointer to the memory region structure + * @range: Pointer to the HMM range structure + * + * This function performs the following steps: + * 1. Reads the notifier sequence for the HMM range. + * 2. Acquires a read lock on the memory map. + * 3. Handles HMM faults for the specified range. + * 4. Releases the read lock on the memory map. + * 5. If successful, locks the memory region mutex. + * 6. Verifies if the notifier sequence has changed during the operation. + * If it has, releases the mutex and returns -EBUSY to match with + * hmm_range_fault() return code for repeating. + * + * Return: 0 on success, a negative error code otherwise. + */ +static int mshv_region_hmm_fault_and_lock(struct mshv_mem_region *region, + struct hmm_range *range) +{ + int ret; + + range->notifier_seq = mmu_interval_read_begin(range->notifier); + mmap_read_lock(region->mni.mm); + ret = hmm_range_fault(range); + mmap_read_unlock(region->mni.mm); + if (ret) + return ret; + + mutex_lock(®ion->mutex); + + if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) { + mutex_unlock(®ion->mutex); + cond_resched(); + return -EBUSY; + } + + return 0; +} + +/** + * mshv_region_range_fault - Handle memory range faults for a given region. + * @region: Pointer to the memory region structure. + * @page_offset: Offset of the page within the region. + * @page_count: Number of pages to handle. + * + * This function resolves memory faults for a specified range of pages + * within a memory region. It uses HMM (Heterogeneous Memory Management) + * to fault in the required pages and updates the region's page array. + * + * Return: 0 on success, negative error code on failure. + */ +static int mshv_region_range_fault(struct mshv_mem_region *region, + u64 page_offset, u64 page_count) +{ + struct hmm_range range = { + .notifier = ®ion->mni, + .default_flags = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE, + }; + unsigned long *pfns; + int ret; + u64 i; + + pfns = kmalloc_array(page_count, sizeof(*pfns), GFP_KERNEL); + if (!pfns) + return -ENOMEM; + + range.hmm_pfns = pfns; + range.start = region->start_uaddr + page_offset * HV_HYP_PAGE_SIZE; + range.end = range.start + page_count * HV_HYP_PAGE_SIZE; + + do { + ret = mshv_region_hmm_fault_and_lock(region, &range); + } while (ret == -EBUSY); + + if (ret) + goto out; + + for (i = 0; i < page_count; i++) + region->pages[page_offset + i] = hmm_pfn_to_page(pfns[i]); + + ret = mshv_region_remap_pages(region, region->hv_map_flags, + page_offset, page_count); + + mutex_unlock(®ion->mutex); +out: + kfree(pfns); + return ret; +} + +bool mshv_region_handle_gfn_fault(struct mshv_mem_region *region, u64 gfn) +{ + u64 page_offset, page_count; + int ret; + + /* Align the page offset to the nearest MSHV_MAP_FAULT_IN_PAGES. */ + page_offset = ALIGN_DOWN(gfn - region->start_gfn, + MSHV_MAP_FAULT_IN_PAGES); + + /* Map more pages than requested to reduce the number of faults. */ + page_count = min(region->nr_pages - page_offset, + MSHV_MAP_FAULT_IN_PAGES); + + ret = mshv_region_range_fault(region, page_offset, page_count); + + WARN_ONCE(ret, + "p%llu: GPA intercept failed: region %#llx-%#llx, gfn %#llx, page_offset %llu, page_count %llu\n", + region->partition->pt_id, region->start_uaddr, + region->start_uaddr + (region->nr_pages << HV_HYP_PAGE_SHIFT), + gfn, page_offset, page_count); + + return !ret; +} + +/** + * mshv_region_interval_invalidate - Invalidate a range of memory region + * @mni: Pointer to the mmu_interval_notifier structure + * @range: Pointer to the mmu_notifier_range structure + * @cur_seq: Current sequence number for the interval notifier + * + * This function invalidates a memory region by remapping its pages with + * no access permissions. It locks the region's mutex to ensure thread safety + * and updates the sequence number for the interval notifier. If the range + * is blockable, it uses a blocking lock; otherwise, it attempts a non-blocking + * lock and returns false if unsuccessful. + * + * NOTE: Failure to invalidate a region is a serious error, as the pages will + * be considered freed while they are still mapped by the hypervisor. + * Any attempt to access such pages will likely crash the system. + * + * Return: true if the region was successfully invalidated, false otherwise. + */ +static bool mshv_region_interval_invalidate(struct mmu_interval_notifier *mni, + const struct mmu_notifier_range *range, + unsigned long cur_seq) +{ + struct mshv_mem_region *region = container_of(mni, + struct mshv_mem_region, + mni); + u64 page_offset, page_count; + unsigned long mstart, mend; + int ret = -EPERM; + + if (mmu_notifier_range_blockable(range)) + mutex_lock(®ion->mutex); + else if (!mutex_trylock(®ion->mutex)) + goto out_fail; + + mmu_interval_set_seq(mni, cur_seq); + + mstart = max(range->start, region->start_uaddr); + mend = min(range->end, region->start_uaddr + + (region->nr_pages << HV_HYP_PAGE_SHIFT)); + + page_offset = HVPFN_DOWN(mstart - region->start_uaddr); + page_count = HVPFN_DOWN(mend - mstart); + + ret = mshv_region_remap_pages(region, HV_MAP_GPA_NO_ACCESS, + page_offset, page_count); + if (ret) + goto out_fail; + + mshv_region_invalidate_pages(region, page_offset, page_count); + + mutex_unlock(®ion->mutex); + + return true; + +out_fail: + WARN_ONCE(ret, + "Failed to invalidate region %#llx-%#llx (range %#lx-%#lx, event: %u, pages %#llx-%#llx, mm: %#llx): %d\n", + region->start_uaddr, + region->start_uaddr + (region->nr_pages << HV_HYP_PAGE_SHIFT), + range->start, range->end, range->event, + page_offset, page_offset + page_count - 1, (u64)range->mm, ret); + return false; +} + +static const struct mmu_interval_notifier_ops mshv_region_mni_ops = { + .invalidate = mshv_region_interval_invalidate, +}; + +void mshv_region_movable_fini(struct mshv_mem_region *region) +{ + mmu_interval_notifier_remove(®ion->mni); +} + +bool mshv_region_movable_init(struct mshv_mem_region *region) +{ + int ret; + + ret = mmu_interval_notifier_insert(®ion->mni, current->mm, + region->start_uaddr, + region->nr_pages << HV_HYP_PAGE_SHIFT, + &mshv_region_mni_ops); + if (ret) + return false; + + mutex_init(®ion->mutex); + + return true; +} diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h index e3931b0f1269..3c1d88b36741 100644 --- a/drivers/hv/mshv_root.h +++ b/drivers/hv/mshv_root.h @@ -15,6 +15,7 @@ #include <linux/hashtable.h> #include <linux/dev_printk.h> #include <linux/build_bug.h> +#include <linux/mmu_notifier.h> #include <uapi/linux/mshv.h> /* @@ -70,18 +71,23 @@ do { \ #define vp_info(v, fmt, ...) vp_devprintk(info, v, fmt, ##__VA_ARGS__) #define vp_dbg(v, fmt, ...) vp_devprintk(dbg, v, fmt, ##__VA_ARGS__) +enum mshv_region_type { + MSHV_REGION_TYPE_MEM_PINNED, + MSHV_REGION_TYPE_MEM_MOVABLE, + MSHV_REGION_TYPE_MMIO +}; + struct mshv_mem_region { struct hlist_node hnode; + struct kref refcount; u64 nr_pages; u64 start_gfn; u64 start_uaddr; u32 hv_map_flags; - struct { - u64 large_pages: 1; /* 2MiB */ - u64 range_pinned: 1; - u64 reserved: 62; - } flags; struct mshv_partition *partition; + enum mshv_region_type type; + struct mmu_interval_notifier mni; + struct mutex mutex; /* protects region pages remapping */ struct page *pages[]; }; @@ -98,6 +104,8 @@ struct mshv_partition { u64 pt_id; refcount_t pt_ref_count; struct mutex pt_mutex; + + spinlock_t pt_mem_regions_lock; struct hlist_head pt_mem_regions; // not ordered u32 pt_vp_count; @@ -169,7 +177,7 @@ struct mshv_girq_routing_table { }; struct hv_synic_pages { - struct hv_message_page *synic_message_page; + struct hv_message_page *hyp_synic_message_page; struct hv_synic_event_flags_page *synic_event_flags_page; struct hv_synic_event_ring_page *synic_event_ring_page; }; @@ -178,6 +186,7 @@ struct mshv_root { struct hv_synic_pages __percpu *synic_pages; spinlock_t pt_ht_lock; DECLARE_HASHTABLE(pt_htable, MSHV_PARTITIONS_HASH_BITS); + struct hv_partition_property_vmm_capabilities vmm_caps; }; /* @@ -278,11 +287,12 @@ int hv_call_set_vp_state(u32 vp_index, u64 partition_id, /* Choose between pages and bytes */ struct hv_vp_state_data state_data, u64 page_count, struct page **pages, u32 num_bytes, u8 *bytes); -int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, - union hv_input_vtl input_vtl, - struct page **state_page); -int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type, - union hv_input_vtl input_vtl); +int hv_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, + union hv_input_vtl input_vtl, + struct page **state_page); +int hv_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type, + struct page *state_page, + union hv_input_vtl input_vtl); int hv_call_create_port(u64 port_partition_id, union hv_port_id port_id, u64 connection_partition_id, struct hv_port_info *port_info, u8 port_vtl, u8 min_connection_vtl, int node); @@ -295,17 +305,32 @@ int hv_call_connect_port(u64 port_partition_id, union hv_port_id port_id, int hv_call_disconnect_port(u64 connection_partition_id, union hv_connection_id connection_id); int hv_call_notify_port_ring_empty(u32 sint_index); -int hv_call_map_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity, - void **addr); -int hv_call_unmap_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity); +int hv_map_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + void **addr); +int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr, + const union hv_stats_object_identity *identity); int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages, u64 page_struct_count, u32 host_access, u32 flags, u8 acquire); +int hv_call_get_partition_property_ex(u64 partition_id, u64 property_code, u64 arg, + void *property_value, size_t property_value_sz); extern struct mshv_root mshv_root; extern enum hv_scheduler_type hv_scheduler_type; extern u8 * __percpu *hv_synic_eventring_tail; +struct mshv_mem_region *mshv_region_create(u64 guest_pfn, u64 nr_pages, + u64 uaddr, u32 flags); +int mshv_region_share(struct mshv_mem_region *region); +int mshv_region_unshare(struct mshv_mem_region *region); +int mshv_region_map(struct mshv_mem_region *region); +void mshv_region_invalidate(struct mshv_mem_region *region); +int mshv_region_pin(struct mshv_mem_region *region); +void mshv_region_put(struct mshv_mem_region *region); +int mshv_region_get(struct mshv_mem_region *region); +bool mshv_region_handle_gfn_fault(struct mshv_mem_region *region, u64 gfn); +void mshv_region_movable_fini(struct mshv_mem_region *region); +bool mshv_region_movable_init(struct mshv_mem_region *region); + #endif /* _MSHV_ROOT_H_ */ diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c index c9c274f29c3c..598eaff4ff29 100644 --- a/drivers/hv/mshv_root_hv_call.c +++ b/drivers/hv/mshv_root_hv_call.c @@ -388,7 +388,13 @@ int hv_call_assert_virtual_interrupt(u64 partition_id, u32 vector, memset(input, 0, sizeof(*input)); input->partition_id = partition_id; input->vector = vector; + /* + * NOTE: dest_addr only needs to be provided while asserting an + * interrupt on x86 platform + */ +#if IS_ENABLED(CONFIG_X86) input->dest_addr = dest_addr; +#endif input->control = control; status = hv_do_hypercall(HVCALL_ASSERT_VIRTUAL_INTERRUPT, input, NULL); local_irq_restore(flags); @@ -526,9 +532,9 @@ int hv_call_set_vp_state(u32 vp_index, u64 partition_id, return ret; } -int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, - union hv_input_vtl input_vtl, - struct page **state_page) +static int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, + union hv_input_vtl input_vtl, + struct page **state_page) { struct hv_input_map_vp_state_page *input; struct hv_output_map_vp_state_page *output; @@ -542,12 +548,20 @@ int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, input = *this_cpu_ptr(hyperv_pcpu_input_arg); output = *this_cpu_ptr(hyperv_pcpu_output_arg); + memset(input, 0, sizeof(*input)); input->partition_id = partition_id; input->vp_index = vp_index; input->type = type; input->input_vtl = input_vtl; - status = hv_do_hypercall(HVCALL_MAP_VP_STATE_PAGE, input, output); + if (*state_page) { + input->flags.map_location_provided = 1; + input->requested_map_location = + page_to_pfn(*state_page); + } + + status = hv_do_hypercall(HVCALL_MAP_VP_STATE_PAGE, input, + output); if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { if (hv_result_success(status)) @@ -565,8 +579,41 @@ int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, return ret; } -int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type, - union hv_input_vtl input_vtl) +static bool mshv_use_overlay_gpfn(void) +{ + return hv_l1vh_partition() && + mshv_root.vmm_caps.vmm_can_provide_overlay_gpfn; +} + +int hv_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, + union hv_input_vtl input_vtl, + struct page **state_page) +{ + int ret = 0; + struct page *allocated_page = NULL; + + if (mshv_use_overlay_gpfn()) { + allocated_page = alloc_page(GFP_KERNEL); + if (!allocated_page) + return -ENOMEM; + *state_page = allocated_page; + } else { + *state_page = NULL; + } + + ret = hv_call_map_vp_state_page(partition_id, vp_index, type, input_vtl, + state_page); + + if (ret && allocated_page) { + __free_page(allocated_page); + *state_page = NULL; + } + + return ret; +} + +static int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type, + union hv_input_vtl input_vtl) { unsigned long flags; u64 status; @@ -590,6 +637,48 @@ int hv_call_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type, return hv_result_to_errno(status); } +int hv_unmap_vp_state_page(u64 partition_id, u32 vp_index, u32 type, + struct page *state_page, union hv_input_vtl input_vtl) +{ + int ret = hv_call_unmap_vp_state_page(partition_id, vp_index, type, input_vtl); + + if (mshv_use_overlay_gpfn() && state_page) + __free_page(state_page); + + return ret; +} + +int hv_call_get_partition_property_ex(u64 partition_id, u64 property_code, + u64 arg, void *property_value, + size_t property_value_sz) +{ + u64 status; + unsigned long flags; + struct hv_input_get_partition_property_ex *input; + struct hv_output_get_partition_property_ex *output; + + local_irq_save(flags); + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + output = *this_cpu_ptr(hyperv_pcpu_output_arg); + + memset(input, 0, sizeof(*input)); + input->partition_id = partition_id; + input->property_code = property_code; + input->arg = arg; + status = hv_do_hypercall(HVCALL_GET_PARTITION_PROPERTY_EX, input, output); + + if (!hv_result_success(status)) { + local_irq_restore(flags); + hv_status_debug(status, "\n"); + return hv_result_to_errno(status); + } + memcpy(property_value, &output->property_value, property_value_sz); + + local_irq_restore(flags); + + return 0; +} + int hv_call_clear_virtual_interrupt(u64 partition_id) { @@ -724,9 +813,51 @@ hv_call_notify_port_ring_empty(u32 sint_index) return hv_result_to_errno(status); } -int hv_call_map_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity, - void **addr) +static int hv_call_map_stats_page2(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + u64 map_location) +{ + unsigned long flags; + struct hv_input_map_stats_page2 *input; + u64 status; + int ret; + + if (!map_location || !mshv_use_overlay_gpfn()) + return -EINVAL; + + do { + local_irq_save(flags); + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + + memset(input, 0, sizeof(*input)); + input->type = type; + input->identity = *identity; + input->map_location = map_location; + + status = hv_do_hypercall(HVCALL_MAP_STATS_PAGE2, input, NULL); + + local_irq_restore(flags); + + ret = hv_result_to_errno(status); + + if (!ret) + break; + + if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { + hv_status_debug(status, "\n"); + break; + } + + ret = hv_call_deposit_pages(NUMA_NO_NODE, + hv_current_partition_id, 1); + } while (!ret); + + return ret; +} + +static int hv_call_map_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + void **addr) { unsigned long flags; struct hv_input_map_stats_page *input; @@ -765,8 +896,38 @@ int hv_call_map_stat_page(enum hv_stats_object_type type, return ret; } -int hv_call_unmap_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity) +int hv_map_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + void **addr) +{ + int ret; + struct page *allocated_page = NULL; + + if (!addr) + return -EINVAL; + + if (mshv_use_overlay_gpfn()) { + allocated_page = alloc_page(GFP_KERNEL); + if (!allocated_page) + return -ENOMEM; + + ret = hv_call_map_stats_page2(type, identity, + page_to_pfn(allocated_page)); + *addr = page_address(allocated_page); + } else { + ret = hv_call_map_stats_page(type, identity, addr); + } + + if (ret && allocated_page) { + __free_page(allocated_page); + *addr = NULL; + } + + return ret; +} + +static int hv_call_unmap_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity) { unsigned long flags; struct hv_input_unmap_stats_page *input; @@ -785,6 +946,19 @@ int hv_call_unmap_stat_page(enum hv_stats_object_type type, return hv_result_to_errno(status); } +int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr, + const union hv_stats_object_identity *identity) +{ + int ret; + + ret = hv_call_unmap_stats_page(type, identity); + + if (mshv_use_overlay_gpfn() && page_addr) + __free_page(virt_to_page(page_addr)); + + return ret; +} + int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages, u64 page_struct_count, u32 host_access, u32 flags, u8 acquire) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index 1d8d8d00e4e0..1134a82c7881 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -42,7 +42,7 @@ MODULE_DESCRIPTION("Microsoft Hyper-V root partition VMM interface /dev/mshv"); /* TODO move this to another file when debugfs code is added */ enum hv_stats_vp_counters { /* HV_THREAD_COUNTER */ #if defined(CONFIG_X86) - VpRootDispatchThreadBlocked = 201, + VpRootDispatchThreadBlocked = 202, #elif defined(CONFIG_ARM64) VpRootDispatchThreadBlocked = 94, #endif @@ -123,6 +123,7 @@ static struct miscdevice mshv_dev = { */ static u16 mshv_passthru_hvcalls[] = { HVCALL_GET_PARTITION_PROPERTY, + HVCALL_GET_PARTITION_PROPERTY_EX, HVCALL_SET_PARTITION_PROPERTY, HVCALL_INSTALL_INTERCEPT, HVCALL_GET_VP_REGISTERS, @@ -137,6 +138,16 @@ static u16 mshv_passthru_hvcalls[] = { HVCALL_GET_VP_CPUID_VALUES, }; +/* + * Only allow hypercalls that are safe to be called by the VMM with the host + * partition as target (i.e. HV_PARTITION_ID_SELF). Carefully audit that a + * hypercall cannot be misused by the VMM before adding it to this list. + */ +static u16 mshv_self_passthru_hvcalls[] = { + HVCALL_GET_PARTITION_PROPERTY, + HVCALL_GET_PARTITION_PROPERTY_EX, +}; + static bool mshv_hvcall_is_async(u16 code) { switch (code) { @@ -148,18 +159,38 @@ static bool mshv_hvcall_is_async(u16 code) return false; } +static bool mshv_passthru_hvcall_allowed(u16 code, u64 pt_id) +{ + int i; + int n = ARRAY_SIZE(mshv_passthru_hvcalls); + u16 *allowed_hvcalls = mshv_passthru_hvcalls; + + if (pt_id == HV_PARTITION_ID_SELF) { + n = ARRAY_SIZE(mshv_self_passthru_hvcalls); + allowed_hvcalls = mshv_self_passthru_hvcalls; + } + + for (i = 0; i < n; ++i) + if (allowed_hvcalls[i] == code) + return true; + + return false; +} + static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition, bool partition_locked, void __user *user_args) { u64 status; - int ret = 0, i; + int ret = 0; bool is_async; struct mshv_root_hvcall args; struct page *page; unsigned int pages_order; void *input_pg = NULL; void *output_pg = NULL; + u16 reps_completed; + u64 pt_id = partition ? partition->pt_id : HV_PARTITION_ID_SELF; if (copy_from_user(&args, user_args, sizeof(args))) return -EFAULT; @@ -171,17 +202,13 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition, if (args.out_ptr && (!args.out_sz || args.out_sz > HV_HYP_PAGE_SIZE)) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(mshv_passthru_hvcalls); ++i) - if (args.code == mshv_passthru_hvcalls[i]) - break; - - if (i >= ARRAY_SIZE(mshv_passthru_hvcalls)) + if (!mshv_passthru_hvcall_allowed(args.code, pt_id)) return -EINVAL; is_async = mshv_hvcall_is_async(args.code); if (is_async) { /* async hypercalls can only be called from partition fd */ - if (!partition_locked) + if (!partition || !partition_locked) return -EINVAL; ret = mshv_init_async_handler(partition); if (ret) @@ -209,43 +236,44 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition, * NOTE: This only works because all the allowed hypercalls' input * structs begin with a u64 partition_id field. */ - *(u64 *)input_pg = partition->pt_id; + *(u64 *)input_pg = pt_id; - if (args.reps) - status = hv_do_rep_hypercall(args.code, args.reps, 0, - input_pg, output_pg); - else - status = hv_do_hypercall(args.code, input_pg, output_pg); - - if (hv_result(status) == HV_STATUS_CALL_PENDING) { - if (is_async) { - mshv_async_hvcall_handler(partition, &status); - } else { /* Paranoia check. This shouldn't happen! */ - ret = -EBADFD; - goto free_pages_out; + reps_completed = 0; + do { + if (args.reps) { + status = hv_do_rep_hypercall_ex(args.code, args.reps, + 0, reps_completed, + input_pg, output_pg); + reps_completed = hv_repcomp(status); + } else { + status = hv_do_hypercall(args.code, input_pg, output_pg); } - } - if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) { - ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id, 1); - if (!ret) - ret = -EAGAIN; - } else if (!hv_result_success(status)) { - ret = hv_result_to_errno(status); - } + if (hv_result(status) == HV_STATUS_CALL_PENDING) { + if (is_async) { + mshv_async_hvcall_handler(partition, &status); + } else { /* Paranoia check. This shouldn't happen! */ + ret = -EBADFD; + goto free_pages_out; + } + } + + if (hv_result_success(status)) + break; + + if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) + ret = hv_result_to_errno(status); + else + ret = hv_call_deposit_pages(NUMA_NO_NODE, + pt_id, 1); + } while (!ret); - /* - * Always return the status and output data regardless of result. - * The VMM may need it to determine how to proceed. E.g. the status may - * contain the number of reps completed if a rep hypercall partially - * succeeded. - */ args.status = hv_result(status); - args.reps = args.reps ? hv_repcomp(status) : 0; + args.reps = reps_completed; if (copy_to_user(user_args, &args, sizeof(args))) ret = -EFAULT; - if (output_pg && + if (!ret && output_pg && copy_to_user((void __user *)args.out_ptr, output_pg, args.out_sz)) ret = -EFAULT; @@ -569,14 +597,98 @@ static long mshv_run_vp_with_root_scheduler(struct mshv_vp *vp) static_assert(sizeof(struct hv_message) <= MSHV_RUN_VP_BUF_SZ, "sizeof(struct hv_message) must not exceed MSHV_RUN_VP_BUF_SZ"); +static struct mshv_mem_region * +mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn) +{ + struct mshv_mem_region *region; + + hlist_for_each_entry(region, &partition->pt_mem_regions, hnode) { + if (gfn >= region->start_gfn && + gfn < region->start_gfn + region->nr_pages) + return region; + } + + return NULL; +} + +#ifdef CONFIG_X86_64 +static struct mshv_mem_region * +mshv_partition_region_by_gfn_get(struct mshv_partition *p, u64 gfn) +{ + struct mshv_mem_region *region; + + spin_lock(&p->pt_mem_regions_lock); + region = mshv_partition_region_by_gfn(p, gfn); + if (!region || !mshv_region_get(region)) { + spin_unlock(&p->pt_mem_regions_lock); + return NULL; + } + spin_unlock(&p->pt_mem_regions_lock); + + return region; +} + +/** + * mshv_handle_gpa_intercept - Handle GPA (Guest Physical Address) intercepts. + * @vp: Pointer to the virtual processor structure. + * + * This function processes GPA intercepts by identifying the memory region + * corresponding to the intercepted GPA, aligning the page offset, and + * mapping the required pages. It ensures that the region is valid and + * handles faults efficiently by mapping multiple pages at once. + * + * Return: true if the intercept was handled successfully, false otherwise. + */ +static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) +{ + struct mshv_partition *p = vp->vp_partition; + struct mshv_mem_region *region; + struct hv_x64_memory_intercept_message *msg; + bool ret; + u64 gfn; + + msg = (struct hv_x64_memory_intercept_message *) + vp->vp_intercept_msg_page->u.payload; + + gfn = HVPFN_DOWN(msg->guest_physical_address); + + region = mshv_partition_region_by_gfn_get(p, gfn); + if (!region) + return false; + + /* Only movable memory ranges are supported for GPA intercepts */ + if (region->type == MSHV_REGION_TYPE_MEM_MOVABLE) + ret = mshv_region_handle_gfn_fault(region, gfn); + else + ret = false; + + mshv_region_put(region); + + return ret; +} +#else /* CONFIG_X86_64 */ +static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) { return false; } +#endif /* CONFIG_X86_64 */ + +static bool mshv_vp_handle_intercept(struct mshv_vp *vp) +{ + switch (vp->vp_intercept_msg_page->header.message_type) { + case HVMSG_GPA_INTERCEPT: + return mshv_handle_gpa_intercept(vp); + } + return false; +} + static long mshv_vp_ioctl_run_vp(struct mshv_vp *vp, void __user *ret_msg) { long rc; - if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) - rc = mshv_run_vp_with_root_scheduler(vp); - else - rc = mshv_run_vp_with_hyp_scheduler(vp); + do { + if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) + rc = mshv_run_vp_with_root_scheduler(vp); + else + rc = mshv_run_vp_with_hyp_scheduler(vp); + } while (rc == 0 && mshv_vp_handle_intercept(vp)); if (rc) return rc; @@ -844,7 +956,8 @@ mshv_vp_release(struct inode *inode, struct file *filp) return 0; } -static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index) +static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index, + void *stats_pages[]) { union hv_stats_object_identity identity = { .vp.partition_id = partition_id, @@ -852,10 +965,10 @@ static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index) }; identity.vp.stats_area_type = HV_STATS_AREA_SELF; - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); identity.vp.stats_area_type = HV_STATS_AREA_PARENT; - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); } static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, @@ -868,14 +981,14 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, int err; identity.vp.stats_area_type = HV_STATS_AREA_SELF; - err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, - &stats_pages[HV_STATS_AREA_SELF]); + err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, + &stats_pages[HV_STATS_AREA_SELF]); if (err) return err; identity.vp.stats_area_type = HV_STATS_AREA_PARENT; - err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, - &stats_pages[HV_STATS_AREA_PARENT]); + err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, + &stats_pages[HV_STATS_AREA_PARENT]); if (err) goto unmap_self; @@ -883,7 +996,7 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, unmap_self: identity.vp.stats_area_type = HV_STATS_AREA_SELF; - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); return err; } @@ -893,7 +1006,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition, { struct mshv_create_vp args; struct mshv_vp *vp; - struct page *intercept_message_page, *register_page, *ghcb_page; + struct page *intercept_msg_page, *register_page, *ghcb_page; void *stats_pages[2]; long ret; @@ -911,33 +1024,34 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition, if (ret) return ret; - ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index, - HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, - input_vtl_zero, - &intercept_message_page); + ret = hv_map_vp_state_page(partition->pt_id, args.vp_index, + HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, + input_vtl_zero, &intercept_msg_page); if (ret) goto destroy_vp; if (!mshv_partition_encrypted(partition)) { - ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index, - HV_VP_STATE_PAGE_REGISTERS, - input_vtl_zero, - ®ister_page); + ret = hv_map_vp_state_page(partition->pt_id, args.vp_index, + HV_VP_STATE_PAGE_REGISTERS, + input_vtl_zero, ®ister_page); if (ret) goto unmap_intercept_message_page; } if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) { - ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index, - HV_VP_STATE_PAGE_GHCB, - input_vtl_normal, - &ghcb_page); + ret = hv_map_vp_state_page(partition->pt_id, args.vp_index, + HV_VP_STATE_PAGE_GHCB, + input_vtl_normal, &ghcb_page); if (ret) goto unmap_register_page; } - if (hv_parent_partition()) { + /* + * This mapping of the stats page is for detecting if dispatch thread + * is blocked - only relevant for root scheduler + */ + if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) { ret = mshv_vp_stats_map(partition->pt_id, args.vp_index, stats_pages); if (ret) @@ -959,14 +1073,14 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition, atomic64_set(&vp->run.vp_signaled_count, 0); vp->vp_index = args.vp_index; - vp->vp_intercept_msg_page = page_to_virt(intercept_message_page); + vp->vp_intercept_msg_page = page_to_virt(intercept_msg_page); if (!mshv_partition_encrypted(partition)) vp->vp_register_page = page_to_virt(register_page); if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) vp->vp_ghcb_page = page_to_virt(ghcb_page); - if (hv_parent_partition()) + if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) memcpy(vp->vp_stats_pages, stats_pages, sizeof(stats_pages)); /* @@ -989,24 +1103,22 @@ put_partition: free_vp: kfree(vp); unmap_stats_pages: - if (hv_parent_partition()) - mshv_vp_stats_unmap(partition->pt_id, args.vp_index); + if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) + mshv_vp_stats_unmap(partition->pt_id, args.vp_index, stats_pages); unmap_ghcb_page: - if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) { - hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index, - HV_VP_STATE_PAGE_GHCB, - input_vtl_normal); - } + if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) + hv_unmap_vp_state_page(partition->pt_id, args.vp_index, + HV_VP_STATE_PAGE_GHCB, ghcb_page, + input_vtl_normal); unmap_register_page: - if (!mshv_partition_encrypted(partition)) { - hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index, - HV_VP_STATE_PAGE_REGISTERS, - input_vtl_zero); - } + if (!mshv_partition_encrypted(partition)) + hv_unmap_vp_state_page(partition->pt_id, args.vp_index, + HV_VP_STATE_PAGE_REGISTERS, + register_page, input_vtl_zero); unmap_intercept_message_page: - hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index, - HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, - input_vtl_zero); + hv_unmap_vp_state_page(partition->pt_id, args.vp_index, + HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, + intercept_msg_page, input_vtl_zero); destroy_vp: hv_call_delete_vp(partition->pt_id, args.vp_index); return ret; @@ -1034,162 +1146,6 @@ static void mshv_async_hvcall_handler(void *data, u64 *status) *status = partition->async_hypercall_status; } -static int -mshv_partition_region_share(struct mshv_mem_region *region) -{ - u32 flags = HV_MODIFY_SPA_PAGE_HOST_ACCESS_MAKE_SHARED; - - if (region->flags.large_pages) - flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; - - return hv_call_modify_spa_host_access(region->partition->pt_id, - region->pages, region->nr_pages, - HV_MAP_GPA_READABLE | HV_MAP_GPA_WRITABLE, - flags, true); -} - -static int -mshv_partition_region_unshare(struct mshv_mem_region *region) -{ - u32 flags = HV_MODIFY_SPA_PAGE_HOST_ACCESS_MAKE_EXCLUSIVE; - - if (region->flags.large_pages) - flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; - - return hv_call_modify_spa_host_access(region->partition->pt_id, - region->pages, region->nr_pages, - 0, - flags, false); -} - -static int -mshv_region_remap_pages(struct mshv_mem_region *region, u32 map_flags, - u64 page_offset, u64 page_count) -{ - if (page_offset + page_count > region->nr_pages) - return -EINVAL; - - if (region->flags.large_pages) - map_flags |= HV_MAP_GPA_LARGE_PAGE; - - /* ask the hypervisor to map guest ram */ - return hv_call_map_gpa_pages(region->partition->pt_id, - region->start_gfn + page_offset, - page_count, map_flags, - region->pages + page_offset); -} - -static int -mshv_region_map(struct mshv_mem_region *region) -{ - u32 map_flags = region->hv_map_flags; - - return mshv_region_remap_pages(region, map_flags, - 0, region->nr_pages); -} - -static void -mshv_region_evict_pages(struct mshv_mem_region *region, - u64 page_offset, u64 page_count) -{ - if (region->flags.range_pinned) - unpin_user_pages(region->pages + page_offset, page_count); - - memset(region->pages + page_offset, 0, - page_count * sizeof(struct page *)); -} - -static void -mshv_region_evict(struct mshv_mem_region *region) -{ - mshv_region_evict_pages(region, 0, region->nr_pages); -} - -static int -mshv_region_populate_pages(struct mshv_mem_region *region, - u64 page_offset, u64 page_count) -{ - u64 done_count, nr_pages; - struct page **pages; - __u64 userspace_addr; - int ret; - - if (page_offset + page_count > region->nr_pages) - return -EINVAL; - - for (done_count = 0; done_count < page_count; done_count += ret) { - pages = region->pages + page_offset + done_count; - userspace_addr = region->start_uaddr + - (page_offset + done_count) * - HV_HYP_PAGE_SIZE; - nr_pages = min(page_count - done_count, - MSHV_PIN_PAGES_BATCH_SIZE); - - /* - * Pinning assuming 4k pages works for large pages too. - * All page structs within the large page are returned. - * - * Pin requests are batched because pin_user_pages_fast - * with the FOLL_LONGTERM flag does a large temporary - * allocation of contiguous memory. - */ - if (region->flags.range_pinned) - ret = pin_user_pages_fast(userspace_addr, - nr_pages, - FOLL_WRITE | FOLL_LONGTERM, - pages); - else - ret = -EOPNOTSUPP; - - if (ret < 0) - goto release_pages; - } - - if (PageHuge(region->pages[page_offset])) - region->flags.large_pages = true; - - return 0; - -release_pages: - mshv_region_evict_pages(region, page_offset, done_count); - return ret; -} - -static int -mshv_region_populate(struct mshv_mem_region *region) -{ - return mshv_region_populate_pages(region, 0, region->nr_pages); -} - -static struct mshv_mem_region * -mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn) -{ - struct mshv_mem_region *region; - - hlist_for_each_entry(region, &partition->pt_mem_regions, hnode) { - if (gfn >= region->start_gfn && - gfn < region->start_gfn + region->nr_pages) - return region; - } - - return NULL; -} - -static struct mshv_mem_region * -mshv_partition_region_by_uaddr(struct mshv_partition *partition, u64 uaddr) -{ - struct mshv_mem_region *region; - - hlist_for_each_entry(region, &partition->pt_mem_regions, hnode) { - if (uaddr >= region->start_uaddr && - uaddr < region->start_uaddr + - (region->nr_pages << HV_HYP_PAGE_SHIFT)) - return region; - } - - return NULL; -} - /* * NB: caller checks and makes sure mem->size is page aligned * Returns: 0 with regionpp updated on success, or -errno @@ -1199,53 +1155,61 @@ static int mshv_partition_create_region(struct mshv_partition *partition, struct mshv_mem_region **regionpp, bool is_mmio) { - struct mshv_mem_region *region; + struct mshv_mem_region *rg; u64 nr_pages = HVPFN_DOWN(mem->size); /* Reject overlapping regions */ - if (mshv_partition_region_by_gfn(partition, mem->guest_pfn) || - mshv_partition_region_by_gfn(partition, mem->guest_pfn + nr_pages - 1) || - mshv_partition_region_by_uaddr(partition, mem->userspace_addr) || - mshv_partition_region_by_uaddr(partition, mem->userspace_addr + mem->size - 1)) + spin_lock(&partition->pt_mem_regions_lock); + hlist_for_each_entry(rg, &partition->pt_mem_regions, hnode) { + if (mem->guest_pfn + nr_pages <= rg->start_gfn || + rg->start_gfn + rg->nr_pages <= mem->guest_pfn) + continue; + spin_unlock(&partition->pt_mem_regions_lock); return -EEXIST; + } + spin_unlock(&partition->pt_mem_regions_lock); - region = vzalloc(sizeof(*region) + sizeof(struct page *) * nr_pages); - if (!region) - return -ENOMEM; - - region->nr_pages = nr_pages; - region->start_gfn = mem->guest_pfn; - region->start_uaddr = mem->userspace_addr; - region->hv_map_flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_ADJUSTABLE; - if (mem->flags & BIT(MSHV_SET_MEM_BIT_WRITABLE)) - region->hv_map_flags |= HV_MAP_GPA_WRITABLE; - if (mem->flags & BIT(MSHV_SET_MEM_BIT_EXECUTABLE)) - region->hv_map_flags |= HV_MAP_GPA_EXECUTABLE; + rg = mshv_region_create(mem->guest_pfn, nr_pages, + mem->userspace_addr, mem->flags); + if (IS_ERR(rg)) + return PTR_ERR(rg); - /* Note: large_pages flag populated when we pin the pages */ - if (!is_mmio) - region->flags.range_pinned = true; + if (is_mmio) + rg->type = MSHV_REGION_TYPE_MMIO; + else if (mshv_partition_encrypted(partition) || + !mshv_region_movable_init(rg)) + rg->type = MSHV_REGION_TYPE_MEM_PINNED; + else + rg->type = MSHV_REGION_TYPE_MEM_MOVABLE; - region->partition = partition; + rg->partition = partition; - *regionpp = region; + *regionpp = rg; return 0; } -/* - * Map guest ram. if snp, make sure to release that from the host first - * Side Effects: In case of failure, pages are unpinned when feasible. +/** + * mshv_prepare_pinned_region - Pin and map memory regions + * @region: Pointer to the memory region structure + * + * This function processes memory regions that are explicitly marked as pinned. + * Pinned regions are preallocated, mapped upfront, and do not rely on fault-based + * population. The function ensures the region is properly populated, handles + * encryption requirements for SNP partitions if applicable, maps the region, + * and performs necessary sharing or eviction operations based on the mapping + * result. + * + * Return: 0 on success, negative error code on failure. */ -static int -mshv_partition_mem_region_map(struct mshv_mem_region *region) +static int mshv_prepare_pinned_region(struct mshv_mem_region *region) { struct mshv_partition *partition = region->partition; int ret; - ret = mshv_region_populate(region); + ret = mshv_region_pin(region); if (ret) { - pt_err(partition, "Failed to populate memory region: %d\n", + pt_err(partition, "Failed to pin memory region: %d\n", ret); goto err_out; } @@ -1258,12 +1222,12 @@ mshv_partition_mem_region_map(struct mshv_mem_region *region) * access to guest memory regions. */ if (mshv_partition_encrypted(partition)) { - ret = mshv_partition_region_unshare(region); + ret = mshv_region_unshare(region); if (ret) { pt_err(partition, "Failed to unshare memory region (guest_pfn: %llu): %d\n", region->start_gfn, ret); - goto evict_region; + goto invalidate_region; } } @@ -1271,9 +1235,9 @@ mshv_partition_mem_region_map(struct mshv_mem_region *region) if (ret && mshv_partition_encrypted(partition)) { int shrc; - shrc = mshv_partition_region_share(region); + shrc = mshv_region_share(region); if (!shrc) - goto evict_region; + goto invalidate_region; pt_err(partition, "Failed to share memory region (guest_pfn: %llu): %d\n", @@ -1287,8 +1251,8 @@ mshv_partition_mem_region_map(struct mshv_mem_region *region) return 0; -evict_region: - mshv_region_evict(region); +invalidate_region: + mshv_region_invalidate(region); err_out: return ret; } @@ -1333,17 +1297,35 @@ mshv_map_user_memory(struct mshv_partition *partition, if (ret) return ret; - if (is_mmio) - ret = hv_call_map_mmio_pages(partition->pt_id, mem.guest_pfn, - mmio_pfn, HVPFN_DOWN(mem.size)); - else - ret = mshv_partition_mem_region_map(region); + switch (region->type) { + case MSHV_REGION_TYPE_MEM_PINNED: + ret = mshv_prepare_pinned_region(region); + break; + case MSHV_REGION_TYPE_MEM_MOVABLE: + /* + * For movable memory regions, remap with no access to let + * the hypervisor track dirty pages, enabling pre-copy live + * migration. + */ + ret = hv_call_map_gpa_pages(partition->pt_id, + region->start_gfn, + region->nr_pages, + HV_MAP_GPA_NO_ACCESS, NULL); + break; + case MSHV_REGION_TYPE_MMIO: + ret = hv_call_map_mmio_pages(partition->pt_id, + region->start_gfn, + mmio_pfn, + region->nr_pages); + break; + } if (ret) goto errout; - /* Install the new region */ + spin_lock(&partition->pt_mem_regions_lock); hlist_add_head(®ion->hnode, &partition->pt_mem_regions); + spin_unlock(&partition->pt_mem_regions_lock); return 0; @@ -1358,33 +1340,32 @@ mshv_unmap_user_memory(struct mshv_partition *partition, struct mshv_user_mem_region mem) { struct mshv_mem_region *region; - u32 unmap_flags = 0; if (!(mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP))) return -EINVAL; + spin_lock(&partition->pt_mem_regions_lock); + region = mshv_partition_region_by_gfn(partition, mem.guest_pfn); - if (!region) - return -EINVAL; + if (!region) { + spin_unlock(&partition->pt_mem_regions_lock); + return -ENOENT; + } /* Paranoia check */ if (region->start_uaddr != mem.userspace_addr || region->start_gfn != mem.guest_pfn || - region->nr_pages != HVPFN_DOWN(mem.size)) + region->nr_pages != HVPFN_DOWN(mem.size)) { + spin_unlock(&partition->pt_mem_regions_lock); return -EINVAL; + } hlist_del(®ion->hnode); - if (region->flags.large_pages) - unmap_flags |= HV_UNMAP_GPA_LARGE_PAGE; - - /* ignore unmap failures and continue as process may be exiting */ - hv_call_unmap_gpa_pages(partition->pt_id, region->start_gfn, - region->nr_pages, unmap_flags); + spin_unlock(&partition->pt_mem_regions_lock); - mshv_region_evict(region); + mshv_region_put(region); - vfree(region); return 0; } @@ -1720,8 +1701,8 @@ static void destroy_partition(struct mshv_partition *partition) { struct mshv_vp *vp; struct mshv_mem_region *region; - int i, ret; struct hlist_node *n; + int i; if (refcount_read(&partition->pt_ref_count)) { pt_err(partition, @@ -1743,28 +1724,32 @@ static void destroy_partition(struct mshv_partition *partition) if (!vp) continue; - if (hv_parent_partition()) - mshv_vp_stats_unmap(partition->pt_id, vp->vp_index); + if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) + mshv_vp_stats_unmap(partition->pt_id, vp->vp_index, + (void **)vp->vp_stats_pages); if (vp->vp_register_page) { - (void)hv_call_unmap_vp_state_page(partition->pt_id, - vp->vp_index, - HV_VP_STATE_PAGE_REGISTERS, - input_vtl_zero); + (void)hv_unmap_vp_state_page(partition->pt_id, + vp->vp_index, + HV_VP_STATE_PAGE_REGISTERS, + virt_to_page(vp->vp_register_page), + input_vtl_zero); vp->vp_register_page = NULL; } - (void)hv_call_unmap_vp_state_page(partition->pt_id, - vp->vp_index, - HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, - input_vtl_zero); + (void)hv_unmap_vp_state_page(partition->pt_id, + vp->vp_index, + HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, + virt_to_page(vp->vp_intercept_msg_page), + input_vtl_zero); vp->vp_intercept_msg_page = NULL; if (vp->vp_ghcb_page) { - (void)hv_call_unmap_vp_state_page(partition->pt_id, - vp->vp_index, - HV_VP_STATE_PAGE_GHCB, - input_vtl_normal); + (void)hv_unmap_vp_state_page(partition->pt_id, + vp->vp_index, + HV_VP_STATE_PAGE_GHCB, + virt_to_page(vp->vp_ghcb_page), + input_vtl_normal); vp->vp_ghcb_page = NULL; } @@ -1781,24 +1766,10 @@ static void destroy_partition(struct mshv_partition *partition) remove_partition(partition); - /* Remove regions, regain access to the memory and unpin the pages */ hlist_for_each_entry_safe(region, n, &partition->pt_mem_regions, hnode) { hlist_del(®ion->hnode); - - if (mshv_partition_encrypted(partition)) { - ret = mshv_partition_region_share(region); - if (ret) { - pt_err(partition, - "Failed to regain access to memory, unpinning user pages will fail and crash the host error: %d\n", - ret); - return; - } - } - - mshv_region_evict(region); - - vfree(region); + mshv_region_put(region); } /* Withdraw and free all pages we deposited */ @@ -1865,41 +1836,117 @@ add_partition(struct mshv_partition *partition) return 0; } -static long -mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev) +static_assert(MSHV_NUM_CPU_FEATURES_BANKS == + HV_PARTITION_PROCESSOR_FEATURES_BANKS); + +static long mshv_ioctl_process_pt_flags(void __user *user_arg, u64 *pt_flags, + struct hv_partition_creation_properties *cr_props, + union hv_partition_isolation_properties *isol_props) { - struct mshv_create_partition args; - u64 creation_flags; - struct hv_partition_creation_properties creation_properties = {}; - union hv_partition_isolation_properties isolation_properties = {}; - struct mshv_partition *partition; - long ret; + int i; + struct mshv_create_partition_v2 args; + union hv_partition_processor_features *disabled_procs; + union hv_partition_processor_xsave_features *disabled_xsave; - if (copy_from_user(&args, user_arg, sizeof(args))) + /* First, copy v1 struct in case user is on previous versions */ + if (copy_from_user(&args, user_arg, + sizeof(struct mshv_create_partition))) return -EFAULT; if ((args.pt_flags & ~MSHV_PT_FLAGS_MASK) || args.pt_isolation >= MSHV_PT_ISOLATION_COUNT) return -EINVAL; + disabled_procs = &cr_props->disabled_processor_features; + disabled_xsave = &cr_props->disabled_processor_xsave_features; + + /* Check if user provided newer struct with feature fields */ + if (args.pt_flags & BIT_ULL(MSHV_PT_BIT_CPU_AND_XSAVE_FEATURES)) { + if (copy_from_user(&args, user_arg, sizeof(args))) + return -EFAULT; + + /* Re-validate v1 fields after second copy_from_user() */ + if ((args.pt_flags & ~MSHV_PT_FLAGS_MASK) || + args.pt_isolation >= MSHV_PT_ISOLATION_COUNT) + return -EINVAL; + + if (args.pt_num_cpu_fbanks != MSHV_NUM_CPU_FEATURES_BANKS || + mshv_field_nonzero(args, pt_rsvd) || + mshv_field_nonzero(args, pt_rsvd1)) + return -EINVAL; + + /* + * Note this assumes MSHV_NUM_CPU_FEATURES_BANKS will never + * change and equals HV_PARTITION_PROCESSOR_FEATURES_BANKS + * (i.e. 2). + * + * Further banks (index >= 2) will be modifiable as 'early' + * properties via the set partition property hypercall. + */ + for (i = 0; i < HV_PARTITION_PROCESSOR_FEATURES_BANKS; i++) + disabled_procs->as_uint64[i] = args.pt_cpu_fbanks[i]; + +#if IS_ENABLED(CONFIG_X86_64) + disabled_xsave->as_uint64 = args.pt_disabled_xsave; +#else + /* + * In practice this field is ignored on arm64, but safer to + * zero it in case it is ever used. + */ + disabled_xsave->as_uint64 = 0; + + if (mshv_field_nonzero(args, pt_rsvd2)) + return -EINVAL; +#endif + } else { + /* + * v1 behavior: try to enable everything. The hypervisor will + * disable features that are not supported. The banks can be + * queried via the get partition property hypercall. + */ + for (i = 0; i < HV_PARTITION_PROCESSOR_FEATURES_BANKS; i++) + disabled_procs->as_uint64[i] = 0; + + disabled_xsave->as_uint64 = 0; + } + /* Only support EXO partitions */ - creation_flags = HV_PARTITION_CREATION_FLAG_EXO_PARTITION | - HV_PARTITION_CREATION_FLAG_INTERCEPT_MESSAGE_PAGE_ENABLED; + *pt_flags = HV_PARTITION_CREATION_FLAG_EXO_PARTITION | + HV_PARTITION_CREATION_FLAG_INTERCEPT_MESSAGE_PAGE_ENABLED; + + if (args.pt_flags & BIT_ULL(MSHV_PT_BIT_LAPIC)) + *pt_flags |= HV_PARTITION_CREATION_FLAG_LAPIC_ENABLED; + if (args.pt_flags & BIT_ULL(MSHV_PT_BIT_X2APIC)) + *pt_flags |= HV_PARTITION_CREATION_FLAG_X2APIC_CAPABLE; + if (args.pt_flags & BIT_ULL(MSHV_PT_BIT_GPA_SUPER_PAGES)) + *pt_flags |= HV_PARTITION_CREATION_FLAG_GPA_SUPER_PAGES_ENABLED; - if (args.pt_flags & BIT(MSHV_PT_BIT_LAPIC)) - creation_flags |= HV_PARTITION_CREATION_FLAG_LAPIC_ENABLED; - if (args.pt_flags & BIT(MSHV_PT_BIT_X2APIC)) - creation_flags |= HV_PARTITION_CREATION_FLAG_X2APIC_CAPABLE; - if (args.pt_flags & BIT(MSHV_PT_BIT_GPA_SUPER_PAGES)) - creation_flags |= HV_PARTITION_CREATION_FLAG_GPA_SUPER_PAGES_ENABLED; + isol_props->as_uint64 = 0; switch (args.pt_isolation) { case MSHV_PT_ISOLATION_NONE: - isolation_properties.isolation_type = - HV_PARTITION_ISOLATION_TYPE_NONE; + isol_props->isolation_type = HV_PARTITION_ISOLATION_TYPE_NONE; break; } + return 0; +} + +static long +mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev) +{ + u64 creation_flags; + struct hv_partition_creation_properties creation_properties; + union hv_partition_isolation_properties isolation_properties; + struct mshv_partition *partition; + long ret; + + ret = mshv_ioctl_process_pt_flags(user_arg, &creation_flags, + &creation_properties, + &isolation_properties); + if (ret) + return ret; + partition = kzalloc(sizeof(*partition), GFP_KERNEL); if (!partition) return -ENOMEM; @@ -1919,6 +1966,7 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev) INIT_HLIST_HEAD(&partition->pt_devices); + spin_lock_init(&partition->pt_mem_regions_lock); INIT_HLIST_HEAD(&partition->pt_mem_regions); mshv_eventfd_init(partition); @@ -1966,6 +2014,9 @@ static long mshv_dev_ioctl(struct file *filp, unsigned int ioctl, case MSHV_CREATE_PARTITION: return mshv_ioctl_create_partition((void __user *)arg, misc->this_device); + case MSHV_ROOT_HVCALL: + return mshv_ioctl_passthru_hvcall(NULL, false, + (void __user *)arg); } return -ENOTTY; @@ -2182,6 +2233,22 @@ root_sched_deinit: return err; } +static void mshv_init_vmm_caps(struct device *dev) +{ + /* + * This can only fail here if HVCALL_GET_PARTITION_PROPERTY_EX or + * HV_PARTITION_PROPERTY_VMM_CAPABILITIES are not supported. In that + * case it's valid to proceed as if all vmm_caps are disabled (zero). + */ + if (hv_call_get_partition_property_ex(HV_PARTITION_ID_SELF, + HV_PARTITION_PROPERTY_VMM_CAPABILITIES, + 0, &mshv_root.vmm_caps, + sizeof(mshv_root.vmm_caps))) + dev_warn(dev, "Unable to get VMM capabilities\n"); + + dev_dbg(dev, "vmm_caps = %#llx\n", mshv_root.vmm_caps.as_uint64[0]); +} + static int __init mshv_parent_partition_init(void) { int ret; @@ -2234,6 +2301,8 @@ static int __init mshv_parent_partition_init(void) if (ret) goto remove_cpu_state; + mshv_init_vmm_caps(dev); + ret = mshv_irqfd_wq_init(); if (ret) goto exit_partition; diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c index e6b6381b7c36..f8b0337cdc82 100644 --- a/drivers/hv/mshv_synic.c +++ b/drivers/hv/mshv_synic.c @@ -394,7 +394,7 @@ unlock_out: void mshv_isr(void) { struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages); - struct hv_message_page **msg_page = &spages->synic_message_page; + struct hv_message_page **msg_page = &spages->hyp_synic_message_page; struct hv_message *msg; bool handled; @@ -456,7 +456,7 @@ int mshv_synic_init(unsigned int cpu) #endif union hv_synic_scontrol sctrl; struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages); - struct hv_message_page **msg_page = &spages->synic_message_page; + struct hv_message_page **msg_page = &spages->hyp_synic_message_page; struct hv_synic_event_flags_page **event_flags_page = &spages->synic_event_flags_page; struct hv_synic_event_ring_page **event_ring_page = @@ -550,7 +550,7 @@ int mshv_synic_cleanup(unsigned int cpu) union hv_synic_sirbp sirbp; union hv_synic_scontrol sctrl; struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages); - struct hv_message_page **msg_page = &spages->synic_message_page; + struct hv_message_page **msg_page = &spages->hyp_synic_message_page; struct hv_synic_event_flags_page **event_flags_page = &spages->synic_event_flags_page; struct hv_synic_event_ring_page **event_ring_page = diff --git a/drivers/hv/mshv_vtl.h b/drivers/hv/mshv_vtl.h new file mode 100644 index 000000000000..a6eea52f7aa2 --- /dev/null +++ b/drivers/hv/mshv_vtl.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _MSHV_VTL_H +#define _MSHV_VTL_H + +#include <linux/mshv.h> +#include <linux/types.h> + +struct mshv_vtl_run { + u32 cancel; + u32 vtl_ret_action_size; + u32 pad[2]; + char exit_message[MSHV_MAX_RUN_MSG_SIZE]; + union { + struct mshv_vtl_cpu_context cpu_context; + + /* + * Reserving room for the cpu context to grow and to maintain compatibility + * with user mode. + */ + char reserved[1024]; + }; + char vtl_ret_actions[MSHV_MAX_RUN_MSG_SIZE]; +}; + +#endif /* _MSHV_VTL_H */ diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c new file mode 100644 index 000000000000..2cebe9de5a5a --- /dev/null +++ b/drivers/hv/mshv_vtl_main.c @@ -0,0 +1,1392 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Microsoft Corporation. + * + * Author: + * Roman Kisel <romank@linux.microsoft.com> + * Saurabh Sengar <ssengar@linux.microsoft.com> + * Naman Jain <namjain@linux.microsoft.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/miscdevice.h> +#include <linux/anon_inodes.h> +#include <linux/cpuhotplug.h> +#include <linux/count_zeros.h> +#include <linux/entry-virt.h> +#include <linux/eventfd.h> +#include <linux/poll.h> +#include <linux/file.h> +#include <linux/vmalloc.h> +#include <asm/debugreg.h> +#include <asm/mshyperv.h> +#include <trace/events/ipi.h> +#include <uapi/asm/mtrr.h> +#include <uapi/linux/mshv.h> +#include <hyperv/hvhdk.h> + +#include "../../kernel/fpu/legacy.h" +#include "mshv.h" +#include "mshv_vtl.h" +#include "hyperv_vmbus.h" + +MODULE_AUTHOR("Microsoft"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Microsoft Hyper-V VTL Driver"); + +#define MSHV_ENTRY_REASON_LOWER_VTL_CALL 0x1 +#define MSHV_ENTRY_REASON_INTERRUPT 0x2 +#define MSHV_ENTRY_REASON_INTERCEPT 0x3 + +#define MSHV_REAL_OFF_SHIFT 16 +#define MSHV_PG_OFF_CPU_MASK (BIT_ULL(MSHV_REAL_OFF_SHIFT) - 1) +#define MSHV_RUN_PAGE_OFFSET 0 +#define MSHV_REG_PAGE_OFFSET 1 +#define VTL2_VMBUS_SINT_INDEX 7 + +static struct device *mem_dev; + +static struct tasklet_struct msg_dpc; +static wait_queue_head_t fd_wait_queue; +static bool has_message; +static struct eventfd_ctx *flag_eventfds[HV_EVENT_FLAGS_COUNT]; +static DEFINE_MUTEX(flag_lock); +static bool __read_mostly mshv_has_reg_page; + +/* hvcall code is of type u16, allocate a bitmap of size (1 << 16) to accommodate it */ +#define MAX_BITMAP_SIZE ((U16_MAX + 1) / 8) + +struct mshv_vtl_hvcall_fd { + u8 allow_bitmap[MAX_BITMAP_SIZE]; + bool allow_map_initialized; + /* + * Used to protect hvcall setup in IOCTLs + */ + struct mutex init_mutex; + struct miscdevice *dev; +}; + +struct mshv_vtl_poll_file { + struct file *file; + wait_queue_entry_t wait; + wait_queue_head_t *wqh; + poll_table pt; + int cpu; +}; + +struct mshv_vtl { + struct device *module_dev; + u64 id; +}; + +struct mshv_vtl_per_cpu { + struct mshv_vtl_run *run; + struct page *reg_page; +}; + +/* SYNIC_OVERLAY_PAGE_MSR - internal, identical to hv_synic_simp */ +union hv_synic_overlay_page_msr { + u64 as_uint64; + struct { + u64 enabled: 1; + u64 reserved: 11; + u64 pfn: 52; + } __packed; +}; + +static struct mutex mshv_vtl_poll_file_lock; +static union hv_register_vsm_page_offsets mshv_vsm_page_offsets; +static union hv_register_vsm_capabilities mshv_vsm_capabilities; + +static DEFINE_PER_CPU(struct mshv_vtl_poll_file, mshv_vtl_poll_file); +static DEFINE_PER_CPU(unsigned long long, num_vtl0_transitions); +static DEFINE_PER_CPU(struct mshv_vtl_per_cpu, mshv_vtl_per_cpu); + +static const union hv_input_vtl input_vtl_zero; +static const union hv_input_vtl input_vtl_normal = { + .use_target_vtl = 1, +}; + +static const struct file_operations mshv_vtl_fops; + +static long +mshv_ioctl_create_vtl(void __user *user_arg, struct device *module_dev) +{ + struct mshv_vtl *vtl; + struct file *file; + int fd; + + vtl = kzalloc(sizeof(*vtl), GFP_KERNEL); + if (!vtl) + return -ENOMEM; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + kfree(vtl); + return fd; + } + file = anon_inode_getfile("mshv_vtl", &mshv_vtl_fops, + vtl, O_RDWR); + if (IS_ERR(file)) { + kfree(vtl); + return PTR_ERR(file); + } + vtl->module_dev = module_dev; + fd_install(fd, file); + + return fd; +} + +static long +mshv_ioctl_check_extension(void __user *user_arg) +{ + u32 arg; + + if (copy_from_user(&arg, user_arg, sizeof(arg))) + return -EFAULT; + + switch (arg) { + case MSHV_CAP_CORE_API_STABLE: + return 0; + case MSHV_CAP_REGISTER_PAGE: + return mshv_has_reg_page; + case MSHV_CAP_VTL_RETURN_ACTION: + return mshv_vsm_capabilities.return_action_available; + case MSHV_CAP_DR6_SHARED: + return mshv_vsm_capabilities.dr6_shared; + } + + return -EOPNOTSUPP; +} + +static long +mshv_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) +{ + struct miscdevice *misc = filp->private_data; + + switch (ioctl) { + case MSHV_CHECK_EXTENSION: + return mshv_ioctl_check_extension((void __user *)arg); + case MSHV_CREATE_VTL: + return mshv_ioctl_create_vtl((void __user *)arg, misc->this_device); + } + + return -ENOTTY; +} + +static const struct file_operations mshv_dev_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = mshv_dev_ioctl, + .llseek = noop_llseek, +}; + +static struct miscdevice mshv_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "mshv", + .fops = &mshv_dev_fops, + .mode = 0600, +}; + +static struct mshv_vtl_run *mshv_vtl_this_run(void) +{ + return *this_cpu_ptr(&mshv_vtl_per_cpu.run); +} + +static struct mshv_vtl_run *mshv_vtl_cpu_run(int cpu) +{ + return *per_cpu_ptr(&mshv_vtl_per_cpu.run, cpu); +} + +static struct page *mshv_vtl_cpu_reg_page(int cpu) +{ + return *per_cpu_ptr(&mshv_vtl_per_cpu.reg_page, cpu); +} + +static void mshv_vtl_configure_reg_page(struct mshv_vtl_per_cpu *per_cpu) +{ + struct hv_register_assoc reg_assoc = {}; + union hv_synic_overlay_page_msr overlay = {}; + struct page *reg_page; + + reg_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_RETRY_MAYFAIL); + if (!reg_page) { + WARN(1, "failed to allocate register page\n"); + return; + } + + overlay.enabled = 1; + overlay.pfn = page_to_hvpfn(reg_page); + reg_assoc.name = HV_X64_REGISTER_REG_PAGE; + reg_assoc.value.reg64 = overlay.as_uint64; + + if (hv_call_set_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF, + 1, input_vtl_zero, ®_assoc)) { + WARN(1, "failed to setup register page\n"); + __free_page(reg_page); + return; + } + + per_cpu->reg_page = reg_page; + mshv_has_reg_page = true; +} + +static void mshv_vtl_synic_enable_regs(unsigned int cpu) +{ + union hv_synic_sint sint; + + sint.as_uint64 = 0; + sint.vector = HYPERVISOR_CALLBACK_VECTOR; + sint.masked = false; + sint.auto_eoi = hv_recommend_using_aeoi(); + + /* Enable intercepts */ + if (!mshv_vsm_capabilities.intercept_page_available) + hv_set_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX, + sint.as_uint64); + + /* VTL2 Host VSP SINT is (un)masked when the user mode requests that */ +} + +static int mshv_vtl_get_vsm_regs(void) +{ + struct hv_register_assoc registers[2]; + int ret, count = 2; + + registers[0].name = HV_REGISTER_VSM_CODE_PAGE_OFFSETS; + registers[1].name = HV_REGISTER_VSM_CAPABILITIES; + + ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF, + count, input_vtl_zero, registers); + if (ret) + return ret; + + mshv_vsm_page_offsets.as_uint64 = registers[0].value.reg64; + mshv_vsm_capabilities.as_uint64 = registers[1].value.reg64; + + return ret; +} + +static int mshv_vtl_configure_vsm_partition(struct device *dev) +{ + union hv_register_vsm_partition_config config; + struct hv_register_assoc reg_assoc; + + config.as_uint64 = 0; + config.default_vtl_protection_mask = HV_MAP_GPA_PERMISSIONS_MASK; + config.enable_vtl_protection = 1; + config.zero_memory_on_reset = 1; + config.intercept_vp_startup = 1; + config.intercept_cpuid_unimplemented = 1; + + if (mshv_vsm_capabilities.intercept_page_available) { + dev_dbg(dev, "using intercept page\n"); + config.intercept_page = 1; + } + + reg_assoc.name = HV_REGISTER_VSM_PARTITION_CONFIG; + reg_assoc.value.reg64 = config.as_uint64; + + return hv_call_set_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF, + 1, input_vtl_zero, ®_assoc); +} + +static void mshv_vtl_vmbus_isr(void) +{ + struct hv_per_cpu_context *per_cpu; + struct hv_message *msg; + u32 message_type; + union hv_synic_event_flags *event_flags; + struct eventfd_ctx *eventfd; + u16 i; + + per_cpu = this_cpu_ptr(hv_context.cpu_context); + if (smp_processor_id() == 0) { + msg = (struct hv_message *)per_cpu->hyp_synic_message_page + VTL2_VMBUS_SINT_INDEX; + message_type = READ_ONCE(msg->header.message_type); + if (message_type != HVMSG_NONE) + tasklet_schedule(&msg_dpc); + } + + event_flags = (union hv_synic_event_flags *)per_cpu->hyp_synic_event_page + + VTL2_VMBUS_SINT_INDEX; + for_each_set_bit(i, event_flags->flags, HV_EVENT_FLAGS_COUNT) { + if (!sync_test_and_clear_bit(i, event_flags->flags)) + continue; + rcu_read_lock(); + eventfd = READ_ONCE(flag_eventfds[i]); + if (eventfd) + eventfd_signal(eventfd); + rcu_read_unlock(); + } + + vmbus_isr(); +} + +static int mshv_vtl_alloc_context(unsigned int cpu) +{ + struct mshv_vtl_per_cpu *per_cpu = this_cpu_ptr(&mshv_vtl_per_cpu); + + per_cpu->run = (struct mshv_vtl_run *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (!per_cpu->run) + return -ENOMEM; + + if (mshv_vsm_capabilities.intercept_page_available) + mshv_vtl_configure_reg_page(per_cpu); + + mshv_vtl_synic_enable_regs(cpu); + + return 0; +} + +static int mshv_vtl_cpuhp_online; + +static int hv_vtl_setup_synic(void) +{ + int ret; + + /* Use our isr to first filter out packets destined for userspace */ + hv_setup_vmbus_handler(mshv_vtl_vmbus_isr); + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vtl:online", + mshv_vtl_alloc_context, NULL); + if (ret < 0) { + hv_setup_vmbus_handler(vmbus_isr); + return ret; + } + + mshv_vtl_cpuhp_online = ret; + + return 0; +} + +static void hv_vtl_remove_synic(void) +{ + cpuhp_remove_state(mshv_vtl_cpuhp_online); + hv_setup_vmbus_handler(vmbus_isr); +} + +static int vtl_get_vp_register(struct hv_register_assoc *reg) +{ + return hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF, + 1, input_vtl_normal, reg); +} + +static int vtl_set_vp_register(struct hv_register_assoc *reg) +{ + return hv_call_set_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF, + 1, input_vtl_normal, reg); +} + +static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg) +{ + struct mshv_vtl_ram_disposition vtl0_mem; + struct dev_pagemap *pgmap; + void *addr; + + if (copy_from_user(&vtl0_mem, arg, sizeof(vtl0_mem))) + return -EFAULT; + /* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design */ + if (vtl0_mem.last_pfn <= vtl0_mem.start_pfn) { + dev_err(vtl->module_dev, "range start pfn (%llx) > end pfn (%llx)\n", + vtl0_mem.start_pfn, vtl0_mem.last_pfn); + return -EFAULT; + } + + pgmap = kzalloc(sizeof(*pgmap), GFP_KERNEL); + if (!pgmap) + return -ENOMEM; + + pgmap->ranges[0].start = PFN_PHYS(vtl0_mem.start_pfn); + pgmap->ranges[0].end = PFN_PHYS(vtl0_mem.last_pfn) - 1; + pgmap->nr_range = 1; + pgmap->type = MEMORY_DEVICE_GENERIC; + + /* + * Determine the highest page order that can be used for the given memory range. + * This works best when the range is aligned; i.e. both the start and the length. + */ + pgmap->vmemmap_shift = count_trailing_zeros(vtl0_mem.start_pfn | vtl0_mem.last_pfn); + dev_dbg(vtl->module_dev, + "Add VTL0 memory: start: 0x%llx, end_pfn: 0x%llx, page order: %lu\n", + vtl0_mem.start_pfn, vtl0_mem.last_pfn, pgmap->vmemmap_shift); + + addr = devm_memremap_pages(mem_dev, pgmap); + if (IS_ERR(addr)) { + dev_err(vtl->module_dev, "devm_memremap_pages error: %ld\n", PTR_ERR(addr)); + kfree(pgmap); + return -EFAULT; + } + + /* Don't free pgmap, since it has to stick around until the memory + * is unmapped, which will never happen as there is no scenario + * where VTL0 can be released/shutdown without bringing down VTL2. + */ + return 0; +} + +static void mshv_vtl_cancel(int cpu) +{ + int here = get_cpu(); + + if (here != cpu) { + if (!xchg_relaxed(&mshv_vtl_cpu_run(cpu)->cancel, 1)) + smp_send_reschedule(cpu); + } else { + WRITE_ONCE(mshv_vtl_this_run()->cancel, 1); + } + put_cpu(); +} + +static int mshv_vtl_poll_file_wake(wait_queue_entry_t *wait, unsigned int mode, int sync, void *key) +{ + struct mshv_vtl_poll_file *poll_file = container_of(wait, struct mshv_vtl_poll_file, wait); + + mshv_vtl_cancel(poll_file->cpu); + + return 0; +} + +static void mshv_vtl_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, poll_table *pt) +{ + struct mshv_vtl_poll_file *poll_file = container_of(pt, struct mshv_vtl_poll_file, pt); + + WARN_ON(poll_file->wqh); + poll_file->wqh = wqh; + add_wait_queue(wqh, &poll_file->wait); +} + +static int mshv_vtl_ioctl_set_poll_file(struct mshv_vtl_set_poll_file __user *user_input) +{ + struct file *file, *old_file; + struct mshv_vtl_poll_file *poll_file; + struct mshv_vtl_set_poll_file input; + + if (copy_from_user(&input, user_input, sizeof(input))) + return -EFAULT; + + if (input.cpu >= num_possible_cpus() || !cpu_online(input.cpu)) + return -EINVAL; + /* + * CPU Hotplug is not supported in VTL2 in OpenHCL, where this kernel driver exists. + * CPU is expected to remain online after above cpu_online() check. + */ + + file = NULL; + file = fget(input.fd); + if (!file) + return -EBADFD; + + poll_file = per_cpu_ptr(&mshv_vtl_poll_file, READ_ONCE(input.cpu)); + if (!poll_file) + return -EINVAL; + + mutex_lock(&mshv_vtl_poll_file_lock); + + if (poll_file->wqh) + remove_wait_queue(poll_file->wqh, &poll_file->wait); + poll_file->wqh = NULL; + + old_file = poll_file->file; + poll_file->file = file; + poll_file->cpu = input.cpu; + + if (file) { + init_waitqueue_func_entry(&poll_file->wait, mshv_vtl_poll_file_wake); + init_poll_funcptr(&poll_file->pt, mshv_vtl_ptable_queue_proc); + vfs_poll(file, &poll_file->pt); + } + + mutex_unlock(&mshv_vtl_poll_file_lock); + + if (old_file) + fput(old_file); + + return 0; +} + +/* Static table mapping register names to their corresponding actions */ +static const struct { + enum hv_register_name reg_name; + int debug_reg_num; /* -1 if not a debug register */ + u32 msr_addr; /* 0 if not an MSR */ +} reg_table[] = { + /* Debug registers */ + {HV_X64_REGISTER_DR0, 0, 0}, + {HV_X64_REGISTER_DR1, 1, 0}, + {HV_X64_REGISTER_DR2, 2, 0}, + {HV_X64_REGISTER_DR3, 3, 0}, + {HV_X64_REGISTER_DR6, 6, 0}, + /* MTRR MSRs */ + {HV_X64_REGISTER_MSR_MTRR_CAP, -1, MSR_MTRRcap}, + {HV_X64_REGISTER_MSR_MTRR_DEF_TYPE, -1, MSR_MTRRdefType}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0, -1, MTRRphysBase_MSR(0)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE1, -1, MTRRphysBase_MSR(1)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE2, -1, MTRRphysBase_MSR(2)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE3, -1, MTRRphysBase_MSR(3)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE4, -1, MTRRphysBase_MSR(4)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE5, -1, MTRRphysBase_MSR(5)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE6, -1, MTRRphysBase_MSR(6)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE7, -1, MTRRphysBase_MSR(7)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE8, -1, MTRRphysBase_MSR(8)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASE9, -1, MTRRphysBase_MSR(9)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASEA, -1, MTRRphysBase_MSR(0xa)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASEB, -1, MTRRphysBase_MSR(0xb)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASEC, -1, MTRRphysBase_MSR(0xc)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASED, -1, MTRRphysBase_MSR(0xd)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASEE, -1, MTRRphysBase_MSR(0xe)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_BASEF, -1, MTRRphysBase_MSR(0xf)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0, -1, MTRRphysMask_MSR(0)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK1, -1, MTRRphysMask_MSR(1)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK2, -1, MTRRphysMask_MSR(2)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK3, -1, MTRRphysMask_MSR(3)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK4, -1, MTRRphysMask_MSR(4)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK5, -1, MTRRphysMask_MSR(5)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK6, -1, MTRRphysMask_MSR(6)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK7, -1, MTRRphysMask_MSR(7)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK8, -1, MTRRphysMask_MSR(8)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASK9, -1, MTRRphysMask_MSR(9)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASKA, -1, MTRRphysMask_MSR(0xa)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASKB, -1, MTRRphysMask_MSR(0xb)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASKC, -1, MTRRphysMask_MSR(0xc)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASKD, -1, MTRRphysMask_MSR(0xd)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASKE, -1, MTRRphysMask_MSR(0xe)}, + {HV_X64_REGISTER_MSR_MTRR_PHYS_MASKF, -1, MTRRphysMask_MSR(0xf)}, + {HV_X64_REGISTER_MSR_MTRR_FIX64K00000, -1, MSR_MTRRfix64K_00000}, + {HV_X64_REGISTER_MSR_MTRR_FIX16K80000, -1, MSR_MTRRfix16K_80000}, + {HV_X64_REGISTER_MSR_MTRR_FIX16KA0000, -1, MSR_MTRRfix16K_A0000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KC0000, -1, MSR_MTRRfix4K_C0000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KC8000, -1, MSR_MTRRfix4K_C8000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KD0000, -1, MSR_MTRRfix4K_D0000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KD8000, -1, MSR_MTRRfix4K_D8000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KE0000, -1, MSR_MTRRfix4K_E0000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KE8000, -1, MSR_MTRRfix4K_E8000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KF0000, -1, MSR_MTRRfix4K_F0000}, + {HV_X64_REGISTER_MSR_MTRR_FIX4KF8000, -1, MSR_MTRRfix4K_F8000}, +}; + +static int mshv_vtl_get_set_reg(struct hv_register_assoc *regs, bool set) +{ + u64 *reg64; + enum hv_register_name gpr_name; + int i; + + gpr_name = regs->name; + reg64 = ®s->value.reg64; + + /* Search for the register in the table */ + for (i = 0; i < ARRAY_SIZE(reg_table); i++) { + if (reg_table[i].reg_name != gpr_name) + continue; + if (reg_table[i].debug_reg_num != -1) { + /* Handle debug registers */ + if (gpr_name == HV_X64_REGISTER_DR6 && + !mshv_vsm_capabilities.dr6_shared) + goto hypercall; + if (set) + native_set_debugreg(reg_table[i].debug_reg_num, *reg64); + else + *reg64 = native_get_debugreg(reg_table[i].debug_reg_num); + } else { + /* Handle MSRs */ + if (set) + wrmsrl(reg_table[i].msr_addr, *reg64); + else + rdmsrl(reg_table[i].msr_addr, *reg64); + } + return 0; + } + +hypercall: + return 1; +} + +static void mshv_vtl_return(struct mshv_vtl_cpu_context *vtl0) +{ + struct hv_vp_assist_page *hvp; + + hvp = hv_vp_assist_page[smp_processor_id()]; + + /* + * Process signal event direct set in the run page, if any. + */ + if (mshv_vsm_capabilities.return_action_available) { + u32 offset = READ_ONCE(mshv_vtl_this_run()->vtl_ret_action_size); + + WRITE_ONCE(mshv_vtl_this_run()->vtl_ret_action_size, 0); + + /* + * Hypervisor will take care of clearing out the actions + * set in the assist page. + */ + memcpy(hvp->vtl_ret_actions, + mshv_vtl_this_run()->vtl_ret_actions, + min_t(u32, offset, sizeof(hvp->vtl_ret_actions))); + } + + mshv_vtl_return_call(vtl0); +} + +static bool mshv_vtl_process_intercept(void) +{ + struct hv_per_cpu_context *mshv_cpu; + void *synic_message_page; + struct hv_message *msg; + u32 message_type; + + mshv_cpu = this_cpu_ptr(hv_context.cpu_context); + synic_message_page = mshv_cpu->hyp_synic_message_page; + if (unlikely(!synic_message_page)) + return true; + + msg = (struct hv_message *)synic_message_page + HV_SYNIC_INTERCEPTION_SINT_INDEX; + message_type = READ_ONCE(msg->header.message_type); + if (message_type == HVMSG_NONE) + return true; + + memcpy(mshv_vtl_this_run()->exit_message, msg, sizeof(*msg)); + vmbus_signal_eom(msg, message_type); + + return false; +} + +static int mshv_vtl_ioctl_return_to_lower_vtl(void) +{ + preempt_disable(); + for (;;) { + unsigned long irq_flags; + struct hv_vp_assist_page *hvp; + int ret; + + if (__xfer_to_guest_mode_work_pending()) { + preempt_enable(); + ret = xfer_to_guest_mode_handle_work(); + if (ret) + return ret; + preempt_disable(); + } + + local_irq_save(irq_flags); + if (READ_ONCE(mshv_vtl_this_run()->cancel)) { + local_irq_restore(irq_flags); + preempt_enable(); + return -EINTR; + } + + mshv_vtl_return(&mshv_vtl_this_run()->cpu_context); + local_irq_restore(irq_flags); + + hvp = hv_vp_assist_page[smp_processor_id()]; + this_cpu_inc(num_vtl0_transitions); + switch (hvp->vtl_entry_reason) { + case MSHV_ENTRY_REASON_INTERRUPT: + if (!mshv_vsm_capabilities.intercept_page_available && + likely(!mshv_vtl_process_intercept())) + goto done; + break; + + case MSHV_ENTRY_REASON_INTERCEPT: + WARN_ON(!mshv_vsm_capabilities.intercept_page_available); + memcpy(mshv_vtl_this_run()->exit_message, hvp->intercept_message, + sizeof(hvp->intercept_message)); + goto done; + + default: + panic("unknown entry reason: %d", hvp->vtl_entry_reason); + } + } + +done: + preempt_enable(); + + return 0; +} + +static long +mshv_vtl_ioctl_get_regs(void __user *user_args) +{ + struct mshv_vp_registers args; + struct hv_register_assoc reg; + long ret; + + if (copy_from_user(&args, user_args, sizeof(args))) + return -EFAULT; + + /* This IOCTL supports processing only one register at a time. */ + if (args.count != 1) + return -EINVAL; + + if (copy_from_user(®, (void __user *)args.regs_ptr, + sizeof(reg))) + return -EFAULT; + + ret = mshv_vtl_get_set_reg(®, false); + if (!ret) + goto copy_args; /* No need of hypercall */ + ret = vtl_get_vp_register(®); + if (ret) + return ret; + +copy_args: + if (copy_to_user((void __user *)args.regs_ptr, ®, sizeof(reg))) + ret = -EFAULT; + + return ret; +} + +static long +mshv_vtl_ioctl_set_regs(void __user *user_args) +{ + struct mshv_vp_registers args; + struct hv_register_assoc reg; + long ret; + + if (copy_from_user(&args, user_args, sizeof(args))) + return -EFAULT; + + /* This IOCTL supports processing only one register at a time. */ + if (args.count != 1) + return -EINVAL; + + if (copy_from_user(®, (void __user *)args.regs_ptr, sizeof(reg))) + return -EFAULT; + + ret = mshv_vtl_get_set_reg(®, true); + if (!ret) + return ret; /* No need of hypercall */ + ret = vtl_set_vp_register(®); + + return ret; +} + +static long +mshv_vtl_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) +{ + long ret; + struct mshv_vtl *vtl = filp->private_data; + + switch (ioctl) { + case MSHV_SET_POLL_FILE: + ret = mshv_vtl_ioctl_set_poll_file((struct mshv_vtl_set_poll_file __user *)arg); + break; + case MSHV_GET_VP_REGISTERS: + ret = mshv_vtl_ioctl_get_regs((void __user *)arg); + break; + case MSHV_SET_VP_REGISTERS: + ret = mshv_vtl_ioctl_set_regs((void __user *)arg); + break; + case MSHV_RETURN_TO_LOWER_VTL: + ret = mshv_vtl_ioctl_return_to_lower_vtl(); + break; + case MSHV_ADD_VTL0_MEMORY: + ret = mshv_vtl_ioctl_add_vtl0_mem(vtl, (void __user *)arg); + break; + default: + dev_err(vtl->module_dev, "invalid vtl ioctl: %#x\n", ioctl); + ret = -ENOTTY; + } + + return ret; +} + +static vm_fault_t mshv_vtl_fault(struct vm_fault *vmf) +{ + struct page *page; + int cpu = vmf->pgoff & MSHV_PG_OFF_CPU_MASK; + int real_off = vmf->pgoff >> MSHV_REAL_OFF_SHIFT; + + if (!cpu_online(cpu)) + return VM_FAULT_SIGBUS; + /* + * CPU Hotplug is not supported in VTL2 in OpenHCL, where this kernel driver exists. + * CPU is expected to remain online after above cpu_online() check. + */ + + if (real_off == MSHV_RUN_PAGE_OFFSET) { + page = virt_to_page(mshv_vtl_cpu_run(cpu)); + } else if (real_off == MSHV_REG_PAGE_OFFSET) { + if (!mshv_has_reg_page) + return VM_FAULT_SIGBUS; + page = mshv_vtl_cpu_reg_page(cpu); + } else { + return VM_FAULT_NOPAGE; + } + + get_page(page); + vmf->page = page; + + return 0; +} + +static const struct vm_operations_struct mshv_vtl_vm_ops = { + .fault = mshv_vtl_fault, +}; + +static int mshv_vtl_mmap(struct file *filp, struct vm_area_struct *vma) +{ + vma->vm_ops = &mshv_vtl_vm_ops; + + return 0; +} + +static int mshv_vtl_release(struct inode *inode, struct file *filp) +{ + struct mshv_vtl *vtl = filp->private_data; + + kfree(vtl); + + return 0; +} + +static const struct file_operations mshv_vtl_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = mshv_vtl_ioctl, + .release = mshv_vtl_release, + .mmap = mshv_vtl_mmap, +}; + +static void mshv_vtl_synic_mask_vmbus_sint(const u8 *mask) +{ + union hv_synic_sint sint; + + sint.as_uint64 = 0; + sint.vector = HYPERVISOR_CALLBACK_VECTOR; + sint.masked = (*mask != 0); + sint.auto_eoi = hv_recommend_using_aeoi(); + + hv_set_msr(HV_MSR_SINT0 + VTL2_VMBUS_SINT_INDEX, + sint.as_uint64); + + if (!sint.masked) + pr_debug("%s: Unmasking VTL2 VMBUS SINT on VP %d\n", __func__, smp_processor_id()); + else + pr_debug("%s: Masking VTL2 VMBUS SINT on VP %d\n", __func__, smp_processor_id()); +} + +static void mshv_vtl_read_remote(void *buffer) +{ + struct hv_per_cpu_context *mshv_cpu = this_cpu_ptr(hv_context.cpu_context); + struct hv_message *msg = (struct hv_message *)mshv_cpu->hyp_synic_message_page + + VTL2_VMBUS_SINT_INDEX; + u32 message_type = READ_ONCE(msg->header.message_type); + + WRITE_ONCE(has_message, false); + if (message_type == HVMSG_NONE) + return; + + memcpy(buffer, msg, sizeof(*msg)); + vmbus_signal_eom(msg, message_type); +} + +static bool vtl_synic_mask_vmbus_sint_masked = true; + +static ssize_t mshv_vtl_sint_read(struct file *filp, char __user *arg, size_t size, loff_t *offset) +{ + struct hv_message msg = {}; + int ret; + + if (size < sizeof(msg)) + return -EINVAL; + + for (;;) { + smp_call_function_single(VMBUS_CONNECT_CPU, mshv_vtl_read_remote, &msg, true); + if (msg.header.message_type != HVMSG_NONE) + break; + + if (READ_ONCE(vtl_synic_mask_vmbus_sint_masked)) + return 0; /* EOF */ + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(fd_wait_queue, + READ_ONCE(has_message) || + READ_ONCE(vtl_synic_mask_vmbus_sint_masked)); + if (ret) + return ret; + } + + if (copy_to_user(arg, &msg, sizeof(msg))) + return -EFAULT; + + return sizeof(msg); +} + +static __poll_t mshv_vtl_sint_poll(struct file *filp, poll_table *wait) +{ + __poll_t mask = 0; + + poll_wait(filp, &fd_wait_queue, wait); + if (READ_ONCE(has_message) || READ_ONCE(vtl_synic_mask_vmbus_sint_masked)) + mask |= EPOLLIN | EPOLLRDNORM; + + return mask; +} + +static void mshv_vtl_sint_on_msg_dpc(unsigned long data) +{ + WRITE_ONCE(has_message, true); + wake_up_interruptible_poll(&fd_wait_queue, EPOLLIN); +} + +static int mshv_vtl_sint_ioctl_post_msg(struct mshv_vtl_sint_post_msg __user *arg) +{ + struct mshv_vtl_sint_post_msg message; + u8 payload[HV_MESSAGE_PAYLOAD_BYTE_COUNT]; + + if (copy_from_user(&message, arg, sizeof(message))) + return -EFAULT; + if (message.payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) + return -EINVAL; + if (copy_from_user(payload, (void __user *)message.payload_ptr, + message.payload_size)) + return -EFAULT; + + return hv_post_message((union hv_connection_id)message.connection_id, + message.message_type, (void *)payload, + message.payload_size); +} + +static int mshv_vtl_sint_ioctl_signal_event(struct mshv_vtl_signal_event __user *arg) +{ + u64 input, status; + struct mshv_vtl_signal_event signal_event; + + if (copy_from_user(&signal_event, arg, sizeof(signal_event))) + return -EFAULT; + + input = signal_event.connection_id | ((u64)signal_event.flag << 32); + + status = hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, input); + + return hv_result_to_errno(status); +} + +static int mshv_vtl_sint_ioctl_set_eventfd(struct mshv_vtl_set_eventfd __user *arg) +{ + struct mshv_vtl_set_eventfd set_eventfd; + struct eventfd_ctx *eventfd, *old_eventfd; + + if (copy_from_user(&set_eventfd, arg, sizeof(set_eventfd))) + return -EFAULT; + if (set_eventfd.flag >= HV_EVENT_FLAGS_COUNT) + return -EINVAL; + + eventfd = NULL; + if (set_eventfd.fd >= 0) { + eventfd = eventfd_ctx_fdget(set_eventfd.fd); + if (IS_ERR(eventfd)) + return PTR_ERR(eventfd); + } + + guard(mutex)(&flag_lock); + old_eventfd = READ_ONCE(flag_eventfds[set_eventfd.flag]); + WRITE_ONCE(flag_eventfds[set_eventfd.flag], eventfd); + + if (old_eventfd) { + synchronize_rcu(); + eventfd_ctx_put(old_eventfd); + } + + return 0; +} + +static int mshv_vtl_sint_ioctl_pause_msg_stream(struct mshv_sint_mask __user *arg) +{ + static DEFINE_MUTEX(vtl2_vmbus_sint_mask_mutex); + struct mshv_sint_mask mask; + + if (copy_from_user(&mask, arg, sizeof(mask))) + return -EFAULT; + guard(mutex)(&vtl2_vmbus_sint_mask_mutex); + on_each_cpu((smp_call_func_t)mshv_vtl_synic_mask_vmbus_sint, &mask.mask, 1); + WRITE_ONCE(vtl_synic_mask_vmbus_sint_masked, mask.mask != 0); + if (mask.mask) + wake_up_interruptible_poll(&fd_wait_queue, EPOLLIN); + + return 0; +} + +static long mshv_vtl_sint_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case MSHV_SINT_POST_MESSAGE: + return mshv_vtl_sint_ioctl_post_msg((struct mshv_vtl_sint_post_msg __user *)arg); + case MSHV_SINT_SIGNAL_EVENT: + return mshv_vtl_sint_ioctl_signal_event((struct mshv_vtl_signal_event __user *)arg); + case MSHV_SINT_SET_EVENTFD: + return mshv_vtl_sint_ioctl_set_eventfd((struct mshv_vtl_set_eventfd __user *)arg); + case MSHV_SINT_PAUSE_MESSAGE_STREAM: + return mshv_vtl_sint_ioctl_pause_msg_stream((struct mshv_sint_mask __user *)arg); + default: + return -ENOIOCTLCMD; + } +} + +static const struct file_operations mshv_vtl_sint_ops = { + .owner = THIS_MODULE, + .read = mshv_vtl_sint_read, + .poll = mshv_vtl_sint_poll, + .unlocked_ioctl = mshv_vtl_sint_ioctl, +}; + +static struct miscdevice mshv_vtl_sint_dev = { + .name = "mshv_sint", + .fops = &mshv_vtl_sint_ops, + .mode = 0600, + .minor = MISC_DYNAMIC_MINOR, +}; + +static int mshv_vtl_hvcall_dev_open(struct inode *node, struct file *f) +{ + struct miscdevice *dev = f->private_data; + struct mshv_vtl_hvcall_fd *fd; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + fd = vzalloc(sizeof(*fd)); + if (!fd) + return -ENOMEM; + fd->dev = dev; + f->private_data = fd; + mutex_init(&fd->init_mutex); + + return 0; +} + +static int mshv_vtl_hvcall_dev_release(struct inode *node, struct file *f) +{ + struct mshv_vtl_hvcall_fd *fd; + + fd = f->private_data; + if (fd) { + vfree(fd); + f->private_data = NULL; + } + + return 0; +} + +static int mshv_vtl_hvcall_do_setup(struct mshv_vtl_hvcall_fd *fd, + struct mshv_vtl_hvcall_setup __user *hvcall_setup_user) +{ + struct mshv_vtl_hvcall_setup hvcall_setup; + + guard(mutex)(&fd->init_mutex); + + if (fd->allow_map_initialized) { + dev_err(fd->dev->this_device, + "Hypercall allow map has already been set, pid %d\n", + current->pid); + return -EINVAL; + } + + if (copy_from_user(&hvcall_setup, hvcall_setup_user, + sizeof(struct mshv_vtl_hvcall_setup))) { + return -EFAULT; + } + if (hvcall_setup.bitmap_array_size > ARRAY_SIZE(fd->allow_bitmap)) + return -EINVAL; + + if (copy_from_user(&fd->allow_bitmap, + (void __user *)hvcall_setup.allow_bitmap_ptr, + hvcall_setup.bitmap_array_size)) { + return -EFAULT; + } + + dev_info(fd->dev->this_device, "Hypercall allow map has been set, pid %d\n", + current->pid); + fd->allow_map_initialized = true; + return 0; +} + +static bool mshv_vtl_hvcall_is_allowed(struct mshv_vtl_hvcall_fd *fd, u16 call_code) +{ + return test_bit(call_code, (unsigned long *)fd->allow_bitmap); +} + +static int mshv_vtl_hvcall_call(struct mshv_vtl_hvcall_fd *fd, + struct mshv_vtl_hvcall __user *hvcall_user) +{ + struct mshv_vtl_hvcall hvcall; + void *in, *out; + int ret; + + if (copy_from_user(&hvcall, hvcall_user, sizeof(struct mshv_vtl_hvcall))) + return -EFAULT; + if (hvcall.input_size > HV_HYP_PAGE_SIZE) + return -EINVAL; + if (hvcall.output_size > HV_HYP_PAGE_SIZE) + return -EINVAL; + + /* + * By default, all hypercalls are not allowed. + * The user mode code has to set up the allow bitmap once. + */ + + if (!mshv_vtl_hvcall_is_allowed(fd, hvcall.control & 0xFFFF)) { + dev_err(fd->dev->this_device, + "Hypercall with control data %#llx isn't allowed\n", + hvcall.control); + return -EPERM; + } + + /* + * This may create a problem for Confidential VM (CVM) usecase where we need to use + * Hyper-V driver allocated per-cpu input and output pages (hyperv_pcpu_input_arg and + * hyperv_pcpu_output_arg) for making a hypervisor call. + * + * TODO: Take care of this when CVM support is added. + */ + in = (void *)__get_free_page(GFP_KERNEL); + out = (void *)__get_free_page(GFP_KERNEL); + + if (copy_from_user(in, (void __user *)hvcall.input_ptr, hvcall.input_size)) { + ret = -EFAULT; + goto free_pages; + } + + hvcall.status = hv_do_hypercall(hvcall.control, in, out); + + if (copy_to_user((void __user *)hvcall.output_ptr, out, hvcall.output_size)) { + ret = -EFAULT; + goto free_pages; + } + ret = put_user(hvcall.status, &hvcall_user->status); +free_pages: + free_page((unsigned long)in); + free_page((unsigned long)out); + + return ret; +} + +static long mshv_vtl_hvcall_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +{ + struct mshv_vtl_hvcall_fd *fd = f->private_data; + + switch (cmd) { + case MSHV_HVCALL_SETUP: + return mshv_vtl_hvcall_do_setup(fd, (struct mshv_vtl_hvcall_setup __user *)arg); + case MSHV_HVCALL: + return mshv_vtl_hvcall_call(fd, (struct mshv_vtl_hvcall __user *)arg); + default: + break; + } + + return -ENOIOCTLCMD; +} + +static const struct file_operations mshv_vtl_hvcall_dev_file_ops = { + .owner = THIS_MODULE, + .open = mshv_vtl_hvcall_dev_open, + .release = mshv_vtl_hvcall_dev_release, + .unlocked_ioctl = mshv_vtl_hvcall_dev_ioctl, +}; + +static struct miscdevice mshv_vtl_hvcall_dev = { + .name = "mshv_hvcall", + .nodename = "mshv_hvcall", + .fops = &mshv_vtl_hvcall_dev_file_ops, + .mode = 0600, + .minor = MISC_DYNAMIC_MINOR, +}; + +static int mshv_vtl_low_open(struct inode *inodep, struct file *filp) +{ + pid_t pid = task_pid_vnr(current); + uid_t uid = current_uid().val; + int ret = 0; + + pr_debug("%s: Opening VTL low, task group %d, uid %d\n", __func__, pid, uid); + + if (capable(CAP_SYS_ADMIN)) { + filp->private_data = inodep; + } else { + pr_err("%s: VTL low open failed: CAP_SYS_ADMIN required. task group %d, uid %d", + __func__, pid, uid); + ret = -EPERM; + } + + return ret; +} + +static bool can_fault(struct vm_fault *vmf, unsigned long size, unsigned long *pfn) +{ + unsigned long mask = size - 1; + unsigned long start = vmf->address & ~mask; + unsigned long end = start + size; + bool is_valid; + + is_valid = (vmf->address & mask) == ((vmf->pgoff << PAGE_SHIFT) & mask) && + start >= vmf->vma->vm_start && + end <= vmf->vma->vm_end; + + if (is_valid) + *pfn = vmf->pgoff & ~(mask >> PAGE_SHIFT); + + return is_valid; +} + +static vm_fault_t mshv_vtl_low_huge_fault(struct vm_fault *vmf, unsigned int order) +{ + unsigned long pfn = vmf->pgoff; + vm_fault_t ret = VM_FAULT_FALLBACK; + + switch (order) { + case 0: + return vmf_insert_mixed(vmf->vma, vmf->address, pfn); + + case PMD_ORDER: + if (can_fault(vmf, PMD_SIZE, &pfn)) + ret = vmf_insert_pfn_pmd(vmf, pfn, vmf->flags & FAULT_FLAG_WRITE); + return ret; + + case PUD_ORDER: + if (can_fault(vmf, PUD_SIZE, &pfn)) + ret = vmf_insert_pfn_pud(vmf, pfn, vmf->flags & FAULT_FLAG_WRITE); + return ret; + + default: + return VM_FAULT_SIGBUS; + } +} + +static vm_fault_t mshv_vtl_low_fault(struct vm_fault *vmf) +{ + return mshv_vtl_low_huge_fault(vmf, 0); +} + +static const struct vm_operations_struct mshv_vtl_low_vm_ops = { + .fault = mshv_vtl_low_fault, + .huge_fault = mshv_vtl_low_huge_fault, +}; + +static int mshv_vtl_low_mmap(struct file *filp, struct vm_area_struct *vma) +{ + vma->vm_ops = &mshv_vtl_low_vm_ops; + vm_flags_set(vma, VM_HUGEPAGE | VM_MIXEDMAP); + + return 0; +} + +static const struct file_operations mshv_vtl_low_file_ops = { + .owner = THIS_MODULE, + .open = mshv_vtl_low_open, + .mmap = mshv_vtl_low_mmap, +}; + +static struct miscdevice mshv_vtl_low = { + .name = "mshv_vtl_low", + .nodename = "mshv_vtl_low", + .fops = &mshv_vtl_low_file_ops, + .mode = 0600, + .minor = MISC_DYNAMIC_MINOR, +}; + +static int __init mshv_vtl_init(void) +{ + int ret; + struct device *dev = mshv_dev.this_device; + + /* + * This creates /dev/mshv which provides functionality to create VTLs and partitions. + */ + ret = misc_register(&mshv_dev); + if (ret) { + dev_err(dev, "mshv device register failed: %d\n", ret); + goto free_dev; + } + + tasklet_init(&msg_dpc, mshv_vtl_sint_on_msg_dpc, 0); + init_waitqueue_head(&fd_wait_queue); + + if (mshv_vtl_get_vsm_regs()) { + dev_emerg(dev, "Unable to get VSM capabilities !!\n"); + ret = -ENODEV; + goto free_dev; + } + if (mshv_vtl_configure_vsm_partition(dev)) { + dev_emerg(dev, "VSM configuration failed !!\n"); + ret = -ENODEV; + goto free_dev; + } + + mshv_vtl_return_call_init(mshv_vsm_page_offsets.vtl_return_offset); + ret = hv_vtl_setup_synic(); + if (ret) + goto free_dev; + + /* + * mshv_sint device adds VMBus relay ioctl support. + * This provides a channel for VTL0 to communicate with VTL2. + */ + ret = misc_register(&mshv_vtl_sint_dev); + if (ret) + goto free_synic; + + /* + * mshv_hvcall device adds interface to enable userspace for direct hypercalls support. + */ + ret = misc_register(&mshv_vtl_hvcall_dev); + if (ret) + goto free_sint; + + /* + * mshv_vtl_low device is used to map VTL0 address space to a user-mode process in VTL2. + * It implements mmap() to allow a user-mode process in VTL2 to map to the address of VTL0. + */ + ret = misc_register(&mshv_vtl_low); + if (ret) + goto free_hvcall; + + /* + * "mshv vtl mem dev" device is later used to setup VTL0 memory. + */ + mem_dev = kzalloc(sizeof(*mem_dev), GFP_KERNEL); + if (!mem_dev) { + ret = -ENOMEM; + goto free_low; + } + + mutex_init(&mshv_vtl_poll_file_lock); + + device_initialize(mem_dev); + dev_set_name(mem_dev, "mshv vtl mem dev"); + ret = device_add(mem_dev); + if (ret) { + dev_err(dev, "mshv vtl mem dev add: %d\n", ret); + goto free_mem; + } + + return 0; + +free_mem: + kfree(mem_dev); +free_low: + misc_deregister(&mshv_vtl_low); +free_hvcall: + misc_deregister(&mshv_vtl_hvcall_dev); +free_sint: + misc_deregister(&mshv_vtl_sint_dev); +free_synic: + hv_vtl_remove_synic(); +free_dev: + misc_deregister(&mshv_dev); + + return ret; +} + +static void __exit mshv_vtl_exit(void) +{ + device_del(mem_dev); + kfree(mem_dev); + misc_deregister(&mshv_vtl_low); + misc_deregister(&mshv_vtl_hvcall_dev); + misc_deregister(&mshv_vtl_sint_dev); + hv_vtl_remove_synic(); + misc_deregister(&mshv_dev); +} + +module_init(mshv_vtl_init); +module_exit(mshv_vtl_exit); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 23ce1fb70de1..3c421a7f78c0 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -184,7 +184,8 @@ void hv_ringbuffer_pre_init(struct vmbus_channel *channel) /* Initialize the ring buffer. */ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, - struct page *pages, u32 page_cnt, u32 max_pkt_size) + struct page *pages, u32 page_cnt, u32 max_pkt_size, + bool confidential) { struct page **pages_wraparound; int i; @@ -208,7 +209,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ring_info->ring_buffer = (struct hv_ring_buffer *) vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, - pgprot_decrypted(PAGE_KERNEL)); + confidential ? PAGE_KERNEL : pgprot_decrypted(PAGE_KERNEL)); kfree(pages_wraparound); if (!ring_info->ring_buffer) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 67734dc73e16..a53af6fe81a6 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -36,6 +36,7 @@ #include <linux/syscore_ops.h> #include <linux/dma-map-ops.h> #include <linux/pci.h> +#include <linux/export.h> #include <clocksource/hyperv_timer.h> #include <asm/mshyperv.h> #include "hyperv_vmbus.h" @@ -57,6 +58,18 @@ int vmbus_irq; int vmbus_interrupt; /* + * If the Confidential VMBus is used, the data on the "wire" is not + * visible to either the host or the hypervisor. + */ +static bool is_confidential; + +bool vmbus_is_confidential(void) +{ + return is_confidential; +} +EXPORT_SYMBOL_GPL(vmbus_is_confidential); + +/* * The panic notifier below is responsible solely for unloading the * vmbus connection, which is necessary in a panic event. * @@ -1045,12 +1058,9 @@ static void vmbus_onmessage_work(struct work_struct *work) kfree(ctx); } -void vmbus_on_msg_dpc(unsigned long data) +static void __vmbus_on_msg_dpc(void *message_page_addr) { - struct hv_per_cpu_context *hv_cpu = (void *)data; - void *page_addr = hv_cpu->synic_message_page; - struct hv_message msg_copy, *msg = (struct hv_message *)page_addr + - VMBUS_MESSAGE_SINT; + struct hv_message msg_copy, *msg; struct vmbus_channel_message_header *hdr; enum vmbus_channel_message_type msgtype; const struct vmbus_channel_message_table_entry *entry; @@ -1058,6 +1068,10 @@ void vmbus_on_msg_dpc(unsigned long data) __u8 payload_size; u32 message_type; + if (!message_page_addr) + return; + msg = (struct hv_message *)message_page_addr + VMBUS_MESSAGE_SINT; + /* * 'enum vmbus_channel_message_type' is supposed to always be 'u32' as * it is being used in 'struct vmbus_channel_message_header' definition @@ -1183,6 +1197,14 @@ msg_handled: vmbus_signal_eom(msg, message_type); } +void vmbus_on_msg_dpc(unsigned long data) +{ + struct hv_per_cpu_context *hv_cpu = (void *)data; + + __vmbus_on_msg_dpc(hv_cpu->hyp_synic_message_page); + __vmbus_on_msg_dpc(hv_cpu->para_synic_message_page); +} + #ifdef CONFIG_PM_SLEEP /* * Fake RESCIND_CHANNEL messages to clean up hv_sock channels by force for @@ -1221,21 +1243,19 @@ static void vmbus_force_channel_rescinded(struct vmbus_channel *channel) #endif /* CONFIG_PM_SLEEP */ /* - * Schedule all channels with events pending + * Schedule all channels with events pending. + * The event page can be directly checked to get the id of + * the channel that has the interrupt pending. */ -static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) +static void vmbus_chan_sched(void *event_page_addr) { unsigned long *recv_int_page; u32 maxbits, relid; + union hv_synic_event_flags *event; - /* - * The event page can be directly checked to get the id of - * the channel that has the interrupt pending. - */ - void *page_addr = hv_cpu->synic_event_page; - union hv_synic_event_flags *event - = (union hv_synic_event_flags *)page_addr + - VMBUS_MESSAGE_SINT; + if (!event_page_addr) + return; + event = (union hv_synic_event_flags *)event_page_addr + VMBUS_MESSAGE_SINT; maxbits = HV_EVENT_FLAGS_COUNT; recv_int_page = event->flags; @@ -1243,6 +1263,11 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) if (unlikely(!recv_int_page)) return; + /* + * Suggested-by: Michael Kelley <mhklinux@outlook.com> + * One possible optimization would be to keep track of the largest relID that's in use, + * and only scan up to that relID. + */ for_each_set_bit(relid, recv_int_page, maxbits) { void (*callback_fn)(void *context); struct vmbus_channel *channel; @@ -1306,29 +1331,39 @@ sched_unlock_rcu: } } -static void vmbus_isr(void) +static void vmbus_message_sched(struct hv_per_cpu_context *hv_cpu, void *message_page_addr) { - struct hv_per_cpu_context *hv_cpu - = this_cpu_ptr(hv_context.cpu_context); - void *page_addr; struct hv_message *msg; - vmbus_chan_sched(hv_cpu); - - page_addr = hv_cpu->synic_message_page; - msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; + if (!message_page_addr) + return; + msg = (struct hv_message *)message_page_addr + VMBUS_MESSAGE_SINT; /* Check if there are actual msgs to be processed */ if (msg->header.message_type != HVMSG_NONE) { if (msg->header.message_type == HVMSG_TIMER_EXPIRED) { hv_stimer0_isr(); vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED); - } else + } else { tasklet_schedule(&hv_cpu->msg_dpc); + } } +} + +void vmbus_isr(void) +{ + struct hv_per_cpu_context *hv_cpu + = this_cpu_ptr(hv_context.cpu_context); + + vmbus_chan_sched(hv_cpu->hyp_synic_event_page); + vmbus_chan_sched(hv_cpu->para_synic_event_page); + + vmbus_message_sched(hv_cpu, hv_cpu->hyp_synic_message_page); + vmbus_message_sched(hv_cpu, hv_cpu->para_synic_message_page); add_interrupt_randomness(vmbus_interrupt); } +EXPORT_SYMBOL_FOR_MODULES(vmbus_isr, "mshv_vtl"); static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) { @@ -1343,6 +1378,59 @@ static void vmbus_percpu_work(struct work_struct *work) hv_synic_init(cpu); } +static int vmbus_alloc_synic_and_connect(void) +{ + int ret, cpu; + struct work_struct __percpu *works; + int hyperv_cpuhp_online; + + ret = hv_synic_alloc(); + if (ret < 0) + goto err_alloc; + + works = alloc_percpu(struct work_struct); + if (!works) { + ret = -ENOMEM; + goto err_alloc; + } + + /* + * Initialize the per-cpu interrupt state and stimer state. + * Then connect to the host. + */ + cpus_read_lock(); + for_each_online_cpu(cpu) { + struct work_struct *work = per_cpu_ptr(works, cpu); + + INIT_WORK(work, vmbus_percpu_work); + schedule_work_on(cpu, work); + } + + for_each_online_cpu(cpu) + flush_work(per_cpu_ptr(works, cpu)); + + /* Register the callbacks for possible CPU online/offline'ing */ + ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", + hv_synic_init, hv_synic_cleanup); + cpus_read_unlock(); + free_percpu(works); + if (ret < 0) + goto err_alloc; + hyperv_cpuhp_online = ret; + + ret = vmbus_connect(); + if (ret) + goto err_connect; + return 0; + +err_connect: + cpuhp_remove_state(hyperv_cpuhp_online); + return -ENODEV; +err_alloc: + hv_synic_free(); + return -ENOMEM; +} + /* * vmbus_bus_init -Main vmbus driver initialization routine. * @@ -1353,8 +1441,7 @@ static void vmbus_percpu_work(struct work_struct *work) */ static int vmbus_bus_init(void) { - int ret, cpu; - struct work_struct __percpu *works; + int ret; ret = hv_init(); if (ret != 0) { @@ -1389,41 +1476,15 @@ static int vmbus_bus_init(void) } } - ret = hv_synic_alloc(); - if (ret) - goto err_alloc; - - works = alloc_percpu(struct work_struct); - if (!works) { - ret = -ENOMEM; - goto err_alloc; - } - /* - * Initialize the per-cpu interrupt state and stimer state. - * Then connect to the host. + * Cache the value as getting it involves a VM exit on x86(_64), and + * doing that on each VP while initializing SynIC's wastes time. */ - cpus_read_lock(); - for_each_online_cpu(cpu) { - struct work_struct *work = per_cpu_ptr(works, cpu); - - INIT_WORK(work, vmbus_percpu_work); - schedule_work_on(cpu, work); - } - - for_each_online_cpu(cpu) - flush_work(per_cpu_ptr(works, cpu)); - - /* Register the callbacks for possible CPU online/offline'ing */ - ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", - hv_synic_init, hv_synic_cleanup); - cpus_read_unlock(); - free_percpu(works); - if (ret < 0) - goto err_alloc; - hyperv_cpuhp_online = ret; - - ret = vmbus_connect(); + is_confidential = ms_hyperv.confidential_vmbus_available; + if (is_confidential) + pr_info("Establishing connection to the confidential VMBus\n"); + hv_para_set_sint_proxy(!is_confidential); + ret = vmbus_alloc_synic_and_connect(); if (ret) goto err_connect; @@ -1439,9 +1500,6 @@ static int vmbus_bus_init(void) return 0; err_connect: - cpuhp_remove_state(hyperv_cpuhp_online); -err_alloc: - hv_synic_free(); if (vmbus_irq == -1) { hv_remove_vmbus_handler(); } else { @@ -2798,7 +2856,7 @@ static void hv_crash_handler(struct pt_regs *regs) */ cpu = smp_processor_id(); hv_stimer_cleanup(cpu); - hv_synic_disable_regs(cpu); + hv_hyp_synic_disable_regs(cpu); }; static int hv_synic_suspend(void *data) @@ -2823,14 +2881,14 @@ static int hv_synic_suspend(void *data) * interrupts-disabled context. */ - hv_synic_disable_regs(0); + hv_hyp_synic_disable_regs(0); return 0; } static void hv_synic_resume(void *data) { - hv_synic_enable_regs(0); + hv_hyp_synic_enable_regs(0); /* * Note: we don't need to call hv_stimer_init(0), because the timer diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 683baf361c4c..a34753fc2973 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -861,9 +861,9 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types if (auto_fan) { /* * The setting affects all fans, so only create a - * single attribute. + * single attribute for the first fan channel. */ - if (channel != 1) + if (channel != 0) return 0; /* diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 60809289f816..ceae96c07ac4 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -593,10 +593,8 @@ static int emc2305_probe_childs_from_dt(struct device *dev) for_each_child_of_node(dev->of_node, child) { if (of_property_present(child, "reg")) { ret = emc2305_of_parse_pwm_child(dev, child, data); - if (ret) { - of_node_put(child); + if (ret) continue; - } count++; } } @@ -685,8 +683,10 @@ static int emc2305_probe(struct i2c_client *client) i = 0; for_each_child_of_node(dev->of_node, child) { ret = emc2305_set_single_tz(dev, child, i); - if (ret != 0) + if (ret != 0) { + of_node_put(child); return ret; + } i++; } } else { diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index ace854b370a0..996e36951f9d 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -218,9 +218,14 @@ static u8 fan_to_reg(long rpm, int div) return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ - ((val) == 255 ? 0 : \ - 1350000 / ((val) * (div)))) +static int fan_from_reg(int val, int div) +{ + if (val == 0) + return -1; + if (val == 255) + return 0; + return 1350000 / (val * div); +} /* for temp1 which is 8-bit resolution, LSB = 1 degree Celsius */ #define TEMP1_FROM_REG(val) ((val) * 1000) @@ -521,7 +526,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ struct w83791d_data *data = w83791d_update_device(dev); \ int nr = sensor_attr->index; \ return sprintf(buf, "%d\n", \ - FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ + fan_from_reg(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } show_fan_reg(fan); @@ -585,10 +590,10 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, if (err) return err; + mutex_lock(&data->update_lock); /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + min = fan_from_reg(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); - mutex_lock(&data->update_lock); data->fan_div[nr] = div_to_reg(nr, val); switch (nr) { diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index fd563e845d4b..a87ecea7f510 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -23,17 +23,8 @@ #include "i2c-algo-pcf.h" -#define DEB2(x) if (i2c_debug >= 2) x -#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */ -#define DEBPROTO(x) if (i2c_debug >= 9) x; - /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 16 -/* - * module parameters: - */ -static int i2c_debug; - /* setting states on the bus with the right timing: */ #define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val) @@ -47,27 +38,21 @@ static int i2c_debug; static void i2c_start(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk(KERN_DEBUG "S ")); set_pcf(adap, 1, I2C_PCF_START); } static void i2c_repstart(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk(" Sr ")); set_pcf(adap, 1, I2C_PCF_REPSTART); } static void i2c_stop(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk("P\n")); set_pcf(adap, 1, I2C_PCF_STOP); } static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) { - DEB2(printk(KERN_INFO - "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n", - *status)); /* * Cleanup from LAB -- reset and enable ESO. * This resets the PCF8584; since we've lost the bus, no @@ -88,9 +73,6 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) if (adap->lab_mdelay) mdelay(adap->lab_mdelay); - DEB2(printk(KERN_INFO - "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", - get_pcf(adap, 1))); } static int wait_for_bb(struct i2c_algo_pcf_data *adap) @@ -147,56 +129,48 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) * * vdovikin: added detect code for PCF8584 */ -static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) +static int pcf_init_8584(struct i2c_algo_pcf_data *adap) { unsigned char temp; - DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", - get_pcf(adap, 1))); - /* S1=0x80: S0 selected, serial interface off */ set_pcf(adap, 1, I2C_PCF_PIN); /* * check to see S1 now used as R/W ctrl - * PCF8584 does that when ESO is zero */ - if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if ((temp & 0x7f) != 0) return -ENXIO; /* definitely not PCF8584 */ - } /* load own address in S0, effective address is (own << 1) */ i2c_outb(adap, get_own(adap)); /* check it's really written */ - if ((temp = i2c_inb(adap)) != get_own(adap)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); + temp = i2c_inb(adap); + if (temp != get_own(adap)) return -ENXIO; - } /* S1=0xA0, next byte in S2 */ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1); /* check to see S2 now selected */ - if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if ((temp & 0x7f) != I2C_PCF_ES1) return -ENXIO; - } /* load clock register S2 */ i2c_outb(adap, get_clock(adap)); /* check it's really written, the only 5 lowest bits does matter */ - if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); + temp = i2c_inb(adap); + if ((temp & 0x1f) != get_clock(adap)) return -ENXIO; - } /* Enable serial interface, idle, S0 selected */ set_pcf(adap, 1, I2C_PCF_IDLE); /* check to see PCF is really idled and we can access status register */ - if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if (temp != (I2C_PCF_PIN | I2C_PCF_BB)) return -ENXIO; - } printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n"); @@ -209,9 +183,7 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; int wrcount, status, timeout; - for (wrcount=0; wrcount<count; ++wrcount) { - DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n", - buf[wrcount] & 0xff)); + for (wrcount = 0; wrcount < count; ++wrcount) { i2c_outb(adap, buf[wrcount]); timeout = wait_for_pin(adap, &status); if (timeout) { @@ -246,7 +218,8 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, /* increment number of bytes to read by one -- read dummy byte */ for (i = 0; i <= count; i++) { - if ((wfp = wait_for_pin(adap, &status))) { + wfp = wait_for_pin(adap, &status); + if (wfp) { if (wfp == -EINTR) return -EINTR; /* arbitration lost */ @@ -280,7 +253,7 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, } -static int pcf_doAddress(struct i2c_algo_pcf_data *adap, +static void pcf_send_address(struct i2c_algo_pcf_data *adap, struct i2c_msg *msg) { unsigned char addr = i2c_8bit_addr_from_msg(msg); @@ -288,8 +261,6 @@ static int pcf_doAddress(struct i2c_algo_pcf_data *adap, if (msg->flags & I2C_M_REV_DIR_ADDR) addr ^= 1; i2c_outb(adap, addr); - - return 0; } static int pcf_xfer(struct i2c_adapter *i2c_adap, @@ -299,7 +270,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; struct i2c_msg *pmsg; int i; - int ret=0, timeout, status; + int timeout, status; if (adap->xfer_begin) adap->xfer_begin(adap->data); @@ -307,20 +278,15 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, /* Check for bus busy */ timeout = wait_for_bb(adap); if (timeout) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: " - "Timeout waiting for BB in pcf_xfer\n");) i = -EIO; goto out; } - for (i = 0;ret >= 0 && i < num; i++) { - pmsg = &msgs[i]; - - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", - str_read_write(pmsg->flags & I2C_M_RD), - pmsg->len, pmsg->addr, i + 1, num);) + for (i = 0; i < num; i++) { + int ret; - ret = pcf_doAddress(adap, pmsg); + pmsg = &msgs[i]; + pcf_send_address(adap, pmsg); /* Send START */ if (i == 0) @@ -335,8 +301,6 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, goto out; } i2c_stop(adap); - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting " - "for PIN(1) in pcf_xfer\n");) i = -EREMOTEIO; goto out; } @@ -344,35 +308,21 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, /* Check LRB (last rcvd bit - slave ack) */ if (status & I2C_PCF_LRB) { i2c_stop(adap); - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) i = -EREMOTEIO; goto out; } - DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", - i, msgs[i].addr, msgs[i].flags, msgs[i].len);) if (pmsg->flags & I2C_M_RD) { ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); - - if (ret != pmsg->len) { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " - "only read %d bytes.\n",ret)); - } else { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret)); - } } else { ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); - - if (ret != pmsg->len) { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " - "only wrote %d bytes.\n",ret)); - } else { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret)); - } } + + if (ret < 0) + goto out; } out: @@ -401,12 +351,11 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap) struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; int rval; - DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); - /* register new adapter to i2c module... */ adap->algo = &pcf_algo; - if ((rval = pcf_init_8584(pcf_adap))) + rval = pcf_init_8584(pcf_adap); + if (rval) return rval; rval = i2c_add_adapter(adap); @@ -418,7 +367,3 @@ EXPORT_SYMBOL(i2c_pcf_add_bus); MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); MODULE_LICENSE("GPL"); - -module_param(i2c_debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index fd81e49638aa..cea87fcb4a1a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -166,6 +166,7 @@ config I2C_I801 Arrow Lake (SOC) Panther Lake (SOC) Wildcat Lake (SOC) + Diamond Rapids (SOC) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -1474,7 +1475,7 @@ config I2C_ACORN config I2C_ELEKTOR tristate "Elektor ISA card" - depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP + depends on ISA && HAS_IOPORT_MAP select I2C_ALGOPCF help This supports the PCF8584 ISA bus I2C adapter. Say Y if you own diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index ef7370d3dbea..60edbabc2986 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -458,13 +458,16 @@ struct amd_mp2_dev *amd_mp2_find_device(void) { struct device *dev; struct pci_dev *pci_dev; + struct amd_mp2_dev *mp2_dev; dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL); if (!dev) return NULL; pci_dev = to_pci_dev(dev); - return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + mp2_dev = (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + put_device(dev); + return mp2_dev; } EXPORT_SYMBOL_GPL(amd_mp2_find_device); diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 8554e790f8e3..0d7e2654a534 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -137,12 +137,14 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_bcm2835_i2c_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate); + u32 divider = clk_bcm2835_i2c_calc_divider(req->rate, req->best_parent_rate); - return DIV_ROUND_UP(*parent_rate, divider); + req->rate = DIV_ROUND_UP(req->best_parent_rate, divider); + + return 0; } static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, @@ -156,7 +158,7 @@ static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, static const struct clk_ops clk_bcm2835_i2c_ops = { .set_rate = clk_bcm2835_i2c_set_rate, - .round_rate = clk_bcm2835_i2c_round_rate, + .determine_rate = clk_bcm2835_i2c_determine_rate, .recalc_rate = clk_bcm2835_i2c_recalc_rate, }; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 347843b4f5dd..bb5ce0a382f9 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -78,6 +78,7 @@ #define DW_IC_TX_ABRT_SOURCE 0x80 #define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_SMBUS_INTR_MASK 0xcc #define DW_IC_COMP_PARAM_1 0xf4 #define DW_IC_COMP_VERSION 0xf8 #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */ @@ -330,7 +331,6 @@ struct dw_i2c_dev { struct i2c_dw_semaphore_callbacks { int (*probe)(struct dw_i2c_dev *dev); - void (*remove)(struct dw_i2c_dev *dev); }; int i2c_dw_init_regmap(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 41e9b5ecad20..45bfca05bb30 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -220,6 +220,13 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) /* Disable the adapter */ __i2c_dw_disable(dev); + /* + * Mask SMBus interrupts to block storms from broken + * firmware that leaves IC_SMBUS=1; the handler never + * services them. + */ + regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0); + /* Write standard speed timing parameters */ regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt); regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 34d881572351..7be99656a67d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -197,15 +197,6 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) return 0; } -static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) -{ - if (dev->semaphore_idx < 0) - return; - - if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove) - i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev); -} - static int dw_i2c_plat_probe(struct platform_device *pdev) { u32 flags = (uintptr_t)device_get_match_data(&pdev->dev); @@ -248,7 +239,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ret = i2c_dw_probe_lock_support(dev); if (ret) { - ret = dev_err_probe(device, ret, "failed to probe lock support\n"); + dev_err_probe(device, ret, "failed to probe lock support\n"); goto exit_reset; } @@ -339,8 +330,6 @@ static void dw_i2c_plat_remove(struct platform_device *pdev) i2c_dw_prepare_clk(dev, false); - i2c_dw_remove_lock_support(dev); - reset_control_assert(dev->rst); } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 57fbec1259be..81e6e2d7ad3d 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -84,6 +84,7 @@ * Panther Lake-H (SOC) 0xe322 32 hard yes yes yes * Panther Lake-P (SOC) 0xe422 32 hard yes yes yes * Wildcat Lake-U (SOC) 0x4d22 32 hard yes yes yes + * Diamond Rapids (SOC) 0x5827 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -242,6 +243,7 @@ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS 0x54a3 #define PCI_DEVICE_ID_INTEL_BIRCH_STREAM_SMBUS 0x5796 +#define PCI_DEVICE_ID_INTEL_DIAMOND_RAPIDS_SMBUS 0x5827 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_ARROW_LAKE_H_SMBUS 0x7722 #define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS 0x7a23 @@ -1054,6 +1056,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, DIAMOND_RAPIDS_SMBUS, FEATURES_ICH5) }, { PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c index 6b918770e612..d42c03ef5db5 100644 --- a/drivers/i2c/busses/i2c-k1.c +++ b/drivers/i2c/busses/i2c-k1.c @@ -158,11 +158,16 @@ static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c) { dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status); - if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) { + /* Arbitration Loss Detected */ + if (i2c->status & SPACEMIT_SR_ALD) { spacemit_i2c_reset(i2c); return -EAGAIN; } + /* Bus Error No ACK/NAK */ + if (i2c->status & SPACEMIT_SR_BED) + spacemit_i2c_reset(i2c); + return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO; } @@ -224,6 +229,12 @@ static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c) } } +static inline void +spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask) +{ + writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); +} + static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) { u32 val; @@ -267,12 +278,8 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) val = readl(i2c->base + SPACEMIT_IRCR); val |= SPACEMIT_RCR_SDA_GLITCH_NOFIX; writel(val, i2c->base + SPACEMIT_IRCR); -} -static inline void -spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask) -{ - writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); } static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index e631d79baf14..884055df1560 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -783,8 +783,54 @@ static const struct cci_data cci_v2_data = { }, }; +static const struct cci_data cci_msm8953_data = { + .num_masters = 2, + .queue_size = { 64, 16 }, + .quirks = { + .max_write_len = 11, + .max_read_len = 12, + }, + .params[I2C_MODE_STANDARD] = { + .thigh = 78, + .tlow = 114, + .tsu_sto = 28, + .tsu_sta = 28, + .thd_dat = 10, + .thd_sta = 77, + .tbuf = 118, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 1 + }, + .params[I2C_MODE_FAST] = { + .thigh = 20, + .tlow = 28, + .tsu_sto = 21, + .tsu_sta = 21, + .thd_dat = 13, + .thd_sta = 18, + .tbuf = 32, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 3 + }, + .params[I2C_MODE_FAST_PLUS] = { + .thigh = 16, + .tlow = 22, + .tsu_sto = 17, + .tsu_sta = 18, + .thd_dat = 16, + .thd_sta = 15, + .tbuf = 19, + .scl_stretch_en = 1, + .trdhld = 3, + .tsp = 3 + }, +}; + static const struct of_device_id cci_dt_match[] = { { .compatible = "qcom,msm8226-cci", .data = &cci_v1_data}, + { .compatible = "qcom,msm8953-cci", .data = &cci_msm8953_data}, { .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data}, { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data}, diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 43fdd89b8beb..3a04016db2c3 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -77,6 +77,25 @@ enum geni_i2c_err_code { #define XFER_TIMEOUT HZ #define RST_TIMEOUT HZ +#define QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC 2 + +/** + * struct geni_i2c_gpi_multi_desc_xfer - Structure for multi transfer support + * + * @msg_idx_cnt: Current message index being processed in the transfer + * @unmap_msg_cnt: Number of messages that have been unmapped + * @irq_cnt: Number of transfer completion interrupts received + * @dma_buf: Array of virtual addresses for DMA-safe buffers + * @dma_addr: Array of DMA addresses corresponding to the buffers + */ +struct geni_i2c_gpi_multi_desc_xfer { + u32 msg_idx_cnt; + u32 unmap_msg_cnt; + u32 irq_cnt; + void **dma_buf; + dma_addr_t *dma_addr; +}; + struct geni_i2c_dev { struct geni_se se; u32 tx_wm; @@ -99,6 +118,9 @@ struct geni_i2c_dev { struct dma_chan *rx_c; bool gpi_mode; bool abort_done; + bool is_tx_multi_desc_xfer; + u32 num_msgs; + struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config; }; struct geni_i2c_desc { @@ -499,6 +521,7 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result) { struct geni_i2c_dev *gi2c = cb; + struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer; if (result->result != DMA_TRANS_NOERROR) { dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result); @@ -507,6 +530,11 @@ static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result) dev_dbg(gi2c->se.dev, "DMA xfer has pending: %d\n", result->residue); } + if (gi2c->is_tx_multi_desc_xfer) { + tx_multi_xfer = &gi2c->i2c_multi_desc_config; + tx_multi_xfer->irq_cnt++; + } + complete(&gi2c->done); } @@ -525,7 +553,72 @@ static void geni_i2c_gpi_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, } } -static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, +/** + * geni_i2c_gpi_multi_desc_unmap() - Unmaps DMA buffers post multi message TX transfers + * @gi2c: I2C dev handle + * @msgs: Array of I2C messages + * @peripheral: Pointer to gpi_i2c_config + */ +static void geni_i2c_gpi_multi_desc_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], + struct gpi_i2c_config *peripheral) +{ + u32 msg_xfer_cnt, wr_idx = 0; + struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer = &gi2c->i2c_multi_desc_config; + + msg_xfer_cnt = gi2c->err ? tx_multi_xfer->msg_idx_cnt : tx_multi_xfer->irq_cnt; + + /* Unmap the processed DMA buffers based on the received interrupt count */ + for (; tx_multi_xfer->unmap_msg_cnt < msg_xfer_cnt; tx_multi_xfer->unmap_msg_cnt++) { + wr_idx = tx_multi_xfer->unmap_msg_cnt; + geni_i2c_gpi_unmap(gi2c, &msgs[wr_idx], + tx_multi_xfer->dma_buf[wr_idx], + tx_multi_xfer->dma_addr[wr_idx], + NULL, 0); + + if (tx_multi_xfer->unmap_msg_cnt == gi2c->num_msgs - 1) { + kfree(tx_multi_xfer->dma_buf); + kfree(tx_multi_xfer->dma_addr); + break; + } + } +} + +/** + * geni_i2c_gpi_multi_xfer_timeout_handler() - Handles multi message transfer timeout + * @dev: Pointer to the corresponding dev node + * @multi_xfer: Pointer to the geni_i2c_gpi_multi_desc_xfer + * @transfer_timeout_msecs: Timeout value in milliseconds + * @transfer_comp: Completion object of the transfer + * + * This function waits for the completion of each processed transfer messages + * based on the interrupts generated upon transfer completion. + * + * Return: On success returns 0, -ETIMEDOUT on timeout. + */ +static int geni_i2c_gpi_multi_xfer_timeout_handler(struct device *dev, + struct geni_i2c_gpi_multi_desc_xfer *multi_xfer, + u32 transfer_timeout_msecs, + struct completion *transfer_comp) +{ + int i; + u32 time_left; + + for (i = 0; i < multi_xfer->msg_idx_cnt - 1; i++) { + reinit_completion(transfer_comp); + + if (multi_xfer->msg_idx_cnt != multi_xfer->irq_cnt) { + time_left = wait_for_completion_timeout(transfer_comp, + transfer_timeout_msecs); + if (!time_left) { + dev_err(dev, "%s: Transfer timeout\n", __func__); + return -ETIMEDOUT; + } + } + } + return 0; +} + +static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], struct dma_slave_config *config, dma_addr_t *dma_addr_p, void **buf, unsigned int op, struct dma_chan *dma_chan) { @@ -537,26 +630,45 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, enum dma_transfer_direction dma_dirn; struct dma_async_tx_descriptor *desc; int ret; + struct geni_i2c_gpi_multi_desc_xfer *gi2c_gpi_xfer; + dma_cookie_t cookie; + u32 msg_idx; peripheral = config->peripheral_config; + gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config; + msg_idx = gi2c_gpi_xfer->msg_idx_cnt; - dma_buf = i2c_get_dma_safe_msg_buf(msg, 1); - if (!dma_buf) - return -ENOMEM; + dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1); + if (!dma_buf) { + ret = -ENOMEM; + goto out; + } if (op == I2C_WRITE) map_dirn = DMA_TO_DEVICE; else map_dirn = DMA_FROM_DEVICE; - addr = dma_map_single(gi2c->se.dev->parent, dma_buf, msg->len, map_dirn); + addr = dma_map_single(gi2c->se.dev->parent, dma_buf, + msgs[msg_idx].len, map_dirn); if (dma_mapping_error(gi2c->se.dev->parent, addr)) { - i2c_put_dma_safe_msg_buf(dma_buf, msg, false); - return -ENOMEM; + i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false); + ret = -ENOMEM; + goto out; + } + + if (gi2c->is_tx_multi_desc_xfer) { + flags = DMA_CTRL_ACK; + + /* BEI bit to be cleared for last TRE */ + if (msg_idx == gi2c->num_msgs - 1) + flags |= DMA_PREP_INTERRUPT; + } else { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; } /* set the length as message for rx txn */ - peripheral->rx_len = msg->len; + peripheral->rx_len = msgs[msg_idx].len; peripheral->op = op; ret = dmaengine_slave_config(dma_chan, config); @@ -567,14 +679,21 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, peripheral->set_config = 0; peripheral->multi_msg = true; - flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; if (op == I2C_WRITE) dma_dirn = DMA_MEM_TO_DEV; else dma_dirn = DMA_DEV_TO_MEM; - desc = dmaengine_prep_slave_single(dma_chan, addr, msg->len, dma_dirn, flags); + desc = dmaengine_prep_slave_single(dma_chan, addr, msgs[msg_idx].len, + dma_dirn, flags); + if (!desc && !(flags & DMA_PREP_INTERRUPT)) { + /* Retry with interrupt if not enough TREs */ + flags |= DMA_PREP_INTERRUPT; + desc = dmaengine_prep_slave_single(dma_chan, addr, msgs[msg_idx].len, + dma_dirn, flags); + } + if (!desc) { dev_err(gi2c->se.dev, "prep_slave_sg failed\n"); ret = -EIO; @@ -584,15 +703,48 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, desc->callback_result = i2c_gpi_cb_result; desc->callback_param = gi2c; - dmaengine_submit(desc); - *buf = dma_buf; - *dma_addr_p = addr; + if (!((msgs[msg_idx].flags & I2C_M_RD) && op == I2C_WRITE)) + gi2c_gpi_xfer->msg_idx_cnt++; + cookie = dmaengine_submit(desc); + if (dma_submit_error(cookie)) { + dev_err(gi2c->se.dev, + "%s: dmaengine_submit failed (%d)\n", __func__, cookie); + ret = -EINVAL; + goto err_config; + } + + if (gi2c->is_tx_multi_desc_xfer) { + gi2c_gpi_xfer->dma_buf[msg_idx] = dma_buf; + gi2c_gpi_xfer->dma_addr[msg_idx] = addr; + + dma_async_issue_pending(gi2c->tx_c); + + if ((msg_idx == (gi2c->num_msgs - 1)) || flags & DMA_PREP_INTERRUPT) { + ret = geni_i2c_gpi_multi_xfer_timeout_handler(gi2c->se.dev, gi2c_gpi_xfer, + XFER_TIMEOUT, &gi2c->done); + if (ret) { + dev_err(gi2c->se.dev, + "I2C multi write msg transfer timeout: %d\n", + ret); + gi2c->err = ret; + return ret; + } + } + } else { + /* Non multi descriptor message transfer */ + *buf = dma_buf; + *dma_addr_p = addr; + } return 0; err_config: - dma_unmap_single(gi2c->se.dev->parent, addr, msg->len, map_dirn); - i2c_put_dma_safe_msg_buf(dma_buf, msg, false); + dma_unmap_single(gi2c->se.dev->parent, addr, + msgs[msg_idx].len, map_dirn); + i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false); + +out: + gi2c->err = ret; return ret; } @@ -604,6 +756,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i unsigned long time_left; dma_addr_t tx_addr, rx_addr; void *tx_buf = NULL, *rx_buf = NULL; + struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer; const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; config.peripheral_config = &peripheral; @@ -617,6 +770,41 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i peripheral.set_config = 1; peripheral.multi_msg = false; + gi2c->num_msgs = num; + gi2c->is_tx_multi_desc_xfer = false; + + tx_multi_xfer = &gi2c->i2c_multi_desc_config; + memset(tx_multi_xfer, 0, sizeof(struct geni_i2c_gpi_multi_desc_xfer)); + + /* + * If number of write messages are two and higher then + * configure hardware for multi descriptor transfers with BEI. + */ + if (num >= QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC) { + gi2c->is_tx_multi_desc_xfer = true; + for (i = 0; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) { + /* + * Multi descriptor transfer with BEI + * support is enabled for write transfers. + * TODO: Add BEI optimization support for + * read transfers later. + */ + gi2c->is_tx_multi_desc_xfer = false; + break; + } + } + } + + if (gi2c->is_tx_multi_desc_xfer) { + tx_multi_xfer->dma_buf = kcalloc(num, sizeof(void *), GFP_KERNEL); + tx_multi_xfer->dma_addr = kcalloc(num, sizeof(dma_addr_t), GFP_KERNEL); + if (!tx_multi_xfer->dma_buf || !tx_multi_xfer->dma_addr) { + ret = -ENOMEM; + goto err; + } + } + for (i = 0; i < num; i++) { gi2c->cur = &msgs[i]; gi2c->err = 0; @@ -627,14 +815,16 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i peripheral.stretch = 1; peripheral.addr = msgs[i].addr; + if (i > 0 && (!(msgs[i].flags & I2C_M_RD))) + peripheral.multi_msg = false; - ret = geni_i2c_gpi(gi2c, &msgs[i], &config, + ret = geni_i2c_gpi(gi2c, msgs, &config, &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c); if (ret) goto err; if (msgs[i].flags & I2C_M_RD) { - ret = geni_i2c_gpi(gi2c, &msgs[i], &config, + ret = geni_i2c_gpi(gi2c, msgs, &config, &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c); if (ret) goto err; @@ -642,18 +832,24 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i dma_async_issue_pending(gi2c->rx_c); } - dma_async_issue_pending(gi2c->tx_c); - - time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); - if (!time_left) - gi2c->err = -ETIMEDOUT; + if (!gi2c->is_tx_multi_desc_xfer) { + dma_async_issue_pending(gi2c->tx_c); + time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); + if (!time_left) { + dev_err(gi2c->se.dev, "%s:I2C timeout\n", __func__); + gi2c->err = -ETIMEDOUT; + } + } if (gi2c->err) { ret = gi2c->err; goto err; } - geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + if (!gi2c->is_tx_multi_desc_xfer) + geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + else if (tx_multi_xfer->unmap_msg_cnt != tx_multi_xfer->irq_cnt) + geni_i2c_gpi_multi_desc_unmap(gi2c, msgs, &peripheral); } return num; @@ -662,7 +858,11 @@ err: dev_err(gi2c->se.dev, "GPI transfer failed: %d\n", ret); dmaengine_terminate_sync(gi2c->rx_c); dmaengine_terminate_sync(gi2c->tx_c); - geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + if (gi2c->is_tx_multi_desc_xfer) + geni_i2c_gpi_multi_desc_unmap(gi2c, msgs, &peripheral); + else + geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + return ret; } diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c index f84ec056e36d..becf8977979f 100644 --- a/drivers/i2c/busses/i2c-stm32.c +++ b/drivers/i2c/busses/i2c-stm32.c @@ -27,8 +27,8 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, if (IS_ERR(dma->chan_tx)) { ret = PTR_ERR(dma->chan_tx); if (ret != -ENODEV) - ret = dev_err_probe(dev, ret, - "can't request DMA tx channel\n"); + dev_err_probe(dev, ret, "can't request DMA tx channel\n"); + goto fail_al; } @@ -48,8 +48,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, if (IS_ERR(dma->chan_rx)) { ret = PTR_ERR(dma->chan_rx); if (ret != -ENODEV) - ret = dev_err_probe(dev, ret, - "can't request DMA rx channel\n"); + dev_err_probe(dev, ret, "can't request DMA rx channel\n"); goto fail_tx; } diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index f88f7e19203a..7f606c871648 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1742,11 +1742,10 @@ EXPORT_SYMBOL_GPL(i3c_master_do_daa); struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *buf, size_t len, bool force_bounce, enum dma_data_direction dir) { - struct i3c_dma *dma_xfer __free(kfree) = NULL; void *bounce __free(kfree) = NULL; void *dma_buf = buf; - dma_xfer = kzalloc(sizeof(*dma_xfer), GFP_KERNEL); + struct i3c_dma *dma_xfer __free(kfree) = kzalloc(sizeof(*dma_xfer), GFP_KERNEL); if (!dma_xfer) return NULL; @@ -2819,14 +2818,10 @@ EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot); static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops) { - if (!ops || !ops->bus_init || + if (!ops || !ops->bus_init || !ops->i3c_xfers || !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers) return -EINVAL; - /* Must provide one of priv_xfers (SDR only) or i3c_xfers (all modes) */ - if (!ops->priv_xfers && !ops->i3c_xfers) - return -EINVAL; - if (ops->request_ibi && (!ops->enable_ibi || !ops->disable_ibi || !ops->free_ibi || !ops->recycle_ibi_slot)) @@ -3031,13 +3026,7 @@ int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, struct i3c_xfer *xfers, if (mode != I3C_SDR && !(master->this->info.hdr_cap & BIT(mode))) return -EOPNOTSUPP; - if (master->ops->i3c_xfers) - return master->ops->i3c_xfers(dev, xfers, nxfers, mode); - - if (mode != I3C_SDR) - return -EINVAL; - - return master->ops->priv_xfers(dev, xfers, nxfers); + return master->ops->i3c_xfers(dev, xfers, nxfers, mode); } int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev) diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c index 82ac0b3d057a..6380a38e6d29 100644 --- a/drivers/i3c/master/adi-i3c-master.c +++ b/drivers/i3c/master/adi-i3c-master.c @@ -332,10 +332,9 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, struct i3c_ccc_cmd *cmd) { struct adi_i3c_master *master = to_adi_i3c_master(m); - struct adi_i3c_xfer *xfer __free(kfree) = NULL; struct adi_i3c_cmd *ccmd; - xfer = adi_i3c_master_alloc_xfer(master, 1); + struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, 1); if (!xfer) return -ENOMEM; @@ -365,19 +364,18 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, return 0; } -static int adi_i3c_master_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *xfers, - int nxfers) +static int adi_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *xfers, + int nxfers, enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct adi_i3c_master *master = to_adi_i3c_master(m); - struct adi_i3c_xfer *xfer __free(kfree) = NULL; int i, ret; if (!nxfers) return 0; - xfer = adi_i3c_master_alloc_xfer(master, nxfers); + struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, nxfers); if (!xfer) return -ENOMEM; @@ -777,7 +775,6 @@ static int adi_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, { struct i3c_master_controller *m = i2c_dev_get_master(dev); struct adi_i3c_master *master = to_adi_i3c_master(m); - struct adi_i3c_xfer *xfer __free(kfree) = NULL; int i; if (!nxfers) @@ -786,7 +783,8 @@ static int adi_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, if (xfers[i].flags & I2C_M_TEN) return -EOPNOTSUPP; } - xfer = adi_i3c_master_alloc_xfer(master, nxfers); + + struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, nxfers); if (!xfer) return -ENOMEM; @@ -919,7 +917,7 @@ static const struct i3c_master_controller_ops adi_i3c_master_ops = { .do_daa = adi_i3c_master_do_daa, .supports_ccc_cmd = adi_i3c_master_supports_ccc_cmd, .send_ccc_cmd = adi_i3c_master_send_ccc_cmd, - .priv_xfers = adi_i3c_master_priv_xfers, + .i3c_xfers = adi_i3c_master_i3c_xfers, .i2c_xfers = adi_i3c_master_i2c_xfers, .request_ibi = adi_i3c_master_request_ibi, .enable_ibi = adi_i3c_master_enable_ibi, diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 276592a8222e..889e2ed5bc83 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -902,9 +902,9 @@ rpm_out: return ret; } -static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *i3c_xfers, - int i3c_nxfers) +static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *i3c_xfers, + int i3c_nxfers, enum i3c_xfer_mode mode) { struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); struct i3c_master_controller *m = i3c_dev_get_master(dev); @@ -1498,7 +1498,7 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { .do_daa = dw_i3c_master_daa, .supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd, .send_ccc_cmd = dw_i3c_master_send_ccc_cmd, - .priv_xfers = dw_i3c_master_priv_xfers, + .i3c_xfers = dw_i3c_master_i3c_xfers, .attach_i2c_dev = dw_i3c_master_attach_i2c_dev, .detach_i2c_dev = dw_i3c_master_detach_i2c_dev, .i2c_xfers = dw_i3c_master_i2c_xfers, diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 97b151564d3d..8eb76b8ca2b0 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -720,9 +720,9 @@ static int cdns_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, return ret; } -static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *xfers, - int nxfers) +static int cdns_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *xfers, + int nxfers, enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct cdns_i3c_master *master = to_cdns_i3c_master(m); @@ -1519,7 +1519,7 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = { .detach_i2c_dev = cdns_i3c_master_detach_i2c_dev, .supports_ccc_cmd = cdns_i3c_master_supports_ccc_cmd, .send_ccc_cmd = cdns_i3c_master_send_ccc_cmd, - .priv_xfers = cdns_i3c_master_priv_xfers, + .i3c_xfers = cdns_i3c_master_i3c_xfers, .i2c_xfers = cdns_i3c_master_i2c_xfers, .enable_ibi = cdns_i3c_master_enable_ibi, .disable_ibi = cdns_i3c_master_disable_ibi, diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 47e42cb4dbe7..607d77ab0e54 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -266,9 +266,9 @@ static int i3c_hci_daa(struct i3c_master_controller *m) return hci->cmd->perform_daa(hci); } -static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev, - struct i3c_priv_xfer *i3c_xfers, - int nxfers) +static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_xfer *i3c_xfers, int nxfers, + enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct i3c_hci *hci = to_i3c_hci(m); @@ -515,7 +515,7 @@ static const struct i3c_master_controller_ops i3c_hci_ops = { .bus_cleanup = i3c_hci_bus_cleanup, .do_daa = i3c_hci_daa, .send_ccc_cmd = i3c_hci_send_ccc_cmd, - .priv_xfers = i3c_hci_priv_xfers, + .i3c_xfers = i3c_hci_i3c_xfers, .i2c_xfers = i3c_hci_i2c_xfers, .attach_i3c_dev = i3c_hci_attach_i3c_dev, .reattach_i3c_dev = i3c_hci_reattach_i3c_dev, diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c index 275f7b924288..426a418f29b6 100644 --- a/drivers/i3c/master/renesas-i3c.c +++ b/drivers/i3c/master/renesas-i3c.c @@ -794,8 +794,8 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m, return ret; } -static int renesas_i3c_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer *i3c_xfers, - int i3c_nxfers) +static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_xfers, + int i3c_nxfers, enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct renesas_i3c *i3c = to_renesas_i3c(m); @@ -1282,7 +1282,7 @@ static const struct i3c_master_controller_ops renesas_i3c_ops = { .do_daa = renesas_i3c_daa, .supports_ccc_cmd = renesas_i3c_supports_ccc_cmd, .send_ccc_cmd = renesas_i3c_send_ccc_cmd, - .priv_xfers = renesas_i3c_priv_xfers, + .i3c_xfers = renesas_i3c_i3c_xfers, .attach_i2c_dev = renesas_i3c_attach_i2c_dev, .detach_i2c_dev = renesas_i3c_detach_i2c_dev, .i2c_xfers = renesas_i3c_i2c_xfers, diff --git a/drivers/input/misc/qnap-mcu-input.c b/drivers/input/misc/qnap-mcu-input.c index 76e62f0816c1..3be899bfc114 100644 --- a/drivers/input/misc/qnap-mcu-input.c +++ b/drivers/input/misc/qnap-mcu-input.c @@ -103,7 +103,7 @@ static int qnap_mcu_input_probe(struct platform_device *pdev) input = devm_input_allocate_device(dev); if (!input) - return dev_err_probe(dev, -ENOMEM, "no memory for input device\n"); + return -ENOMEM; idev->input = input; idev->dev = dev; diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 071b7c9bf566..47f4271395a6 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -923,8 +923,8 @@ static int cyttsp5_i2c_probe(struct i2c_client *client) regmap = devm_regmap_init_i2c(client, &config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "regmap allocation failed: %ld\n", - PTR_ERR(regmap)); + dev_err(&client->dev, "regmap allocation failed: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 93d659ff90aa..d6edfab16770 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -389,6 +389,10 @@ static int titsc_parse_dt(struct platform_device *pdev, dev_warn(&pdev->dev, "invalid co-ordinate readouts, resetting it to 5\n"); ts_dev->coordinate_readouts = 5; + } else if (ts_dev->coordinate_readouts > 6) { + dev_warn(&pdev->dev, + "co-ordinate readouts too large, limiting to 6\n"); + ts_dev->coordinate_readouts = 6; } err = of_property_read_u32(node, "ti,charge-delay", diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index df42fdf36ae3..a360749fa076 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -747,8 +747,7 @@ static int zforce_probe(struct i2c_client *client) input_dev = devm_input_allocate_device(&client->dev); if (!input_dev) - return dev_err_probe(&client->dev, -ENOMEM, - "could not allocate input device\n"); + return -ENOMEM; ts->client = client; ts->input = input_dev; diff --git a/drivers/irqchip/irq-loongarch-avec.c b/drivers/irqchip/irq-loongarch-avec.c index bf52dc8345f5..ba556c008cf3 100644 --- a/drivers/irqchip/irq-loongarch-avec.c +++ b/drivers/irqchip/irq-loongarch-avec.c @@ -209,8 +209,9 @@ static void avecintc_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) struct avecintc_data *adata = irq_data_get_irq_chip_data(d); msg->address_hi = 0x0; - msg->address_lo = (loongarch_avec.msi_base_addr | (adata->vec & 0xff) << 4) - | ((cpu_logical_map(adata->cpu & 0xffff)) << 12); + msg->address_lo = (loongarch_avec.msi_base_addr | + (adata->vec & AVEC_IRQ_MASK) << AVEC_IRQ_SHIFT) | + ((cpu_logical_map(adata->cpu & AVEC_CPU_MASK)) << AVEC_CPU_SHIFT); msg->data = 0x0; } diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index 2474fa467a05..31093a8ab67c 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -170,7 +170,7 @@ static int mchp_eic_domain_alloc(struct irq_domain *domain, unsigned int virq, ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); if (ret || hwirq >= MCHP_EIC_NIRQ) - return ret; + return ret ?: -EINVAL; switch (type) { case IRQ_TYPE_EDGE_RISING: diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 104aa5355090..239c1744a926 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -299,6 +299,7 @@ config DM_CRYPT select CRYPTO select CRYPTO_CBC select CRYPTO_ESSIV + select CRYPTO_LIB_MD5 # needed by lmk IV mode help This device-mapper target allows you to create a device that transparently encrypts the data on it. You'll need to activate @@ -546,6 +547,7 @@ config DM_VERITY depends on BLK_DEV_DM select CRYPTO select CRYPTO_HASH + select CRYPTO_LIB_SHA256 select DM_BUFIO help This device-mapper target creates a read-only device that diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index af345dc6fde1..82fdea7dea7a 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -1104,7 +1104,7 @@ static void detached_dev_end_io(struct bio *bio) } kfree(ddip); - bio->bi_end_io(bio); + bio_endio(bio); } static void detached_dev_do_request(struct bcache_device *d, struct bio *bio, @@ -1121,7 +1121,7 @@ static void detached_dev_do_request(struct bcache_device *d, struct bio *bio, ddip = kzalloc(sizeof(struct detached_dev_io_private), GFP_NOIO); if (!ddip) { bio->bi_status = BLK_STS_RESOURCE; - bio->bi_end_io(bio); + bio_endio(bio); return; } @@ -1136,7 +1136,7 @@ static void detached_dev_do_request(struct bcache_device *d, struct bio *bio, if ((bio_op(bio) == REQ_OP_DISCARD) && !bdev_max_discard_sectors(dc->bdev)) - bio->bi_end_io(bio); + detached_dev_end_io(bio); else submit_bio_noacct(bio); } diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index e6d28be11c5c..5235f3e4924b 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1374,7 +1374,7 @@ static void submit_io(struct dm_buffer *b, enum req_op op, unsigned short ioprio { unsigned int n_sectors; sector_t sector; - unsigned int offset, end; + unsigned int offset, end, align; b->end_io = end_io; @@ -1388,9 +1388,11 @@ static void submit_io(struct dm_buffer *b, enum req_op op, unsigned short ioprio b->c->write_callback(b); offset = b->write_start; end = b->write_end; - offset &= -DM_BUFIO_WRITE_ALIGN; - end += DM_BUFIO_WRITE_ALIGN - 1; - end &= -DM_BUFIO_WRITE_ALIGN; + align = max(DM_BUFIO_WRITE_ALIGN, + bdev_physical_block_size(b->c->bdev)); + offset &= -align; + end += align - 1; + end &= -align; if (unlikely(end > b->c->block_size)) end = b->c->block_size; diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index a3c9f74fe2dc..1cda8618d74d 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -139,7 +139,6 @@ struct mapped_device { struct srcu_struct io_barrier; #ifdef CONFIG_BLK_DEV_ZONED - unsigned int nr_zones; void *zone_revalidate_map; struct task_struct *revalidate_map_task; #endif diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 5ef43231fe77..79704fbc523b 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -21,6 +21,7 @@ #include <linux/mempool.h> #include <linux/slab.h> #include <linux/crypto.h> +#include <linux/fips.h> #include <linux/workqueue.h> #include <linux/kthread.h> #include <linux/backing-dev.h> @@ -120,7 +121,6 @@ struct iv_benbi_private { #define LMK_SEED_SIZE 64 /* hash + 0 */ struct iv_lmk_private { - struct crypto_shash *hash_tfm; u8 *seed; }; @@ -254,22 +254,15 @@ static unsigned int max_write_size = 0; module_param(max_write_size, uint, 0644); MODULE_PARM_DESC(max_write_size, "Maximum size of a write request"); -static unsigned get_max_request_sectors(struct dm_target *ti, struct bio *bio) +static unsigned get_max_request_sectors(struct dm_target *ti, struct bio *bio, bool no_split) { struct crypt_config *cc = ti->private; unsigned val, sector_align; bool wrt = op_is_write(bio_op(bio)); - if (wrt) { - /* - * For zoned devices, splitting write operations creates the - * risk of deadlocking queue freeze operations with zone write - * plugging BIO work when the reminder of a split BIO is - * issued. So always allow the entire BIO to proceed. - */ - if (ti->emulate_zone_append) - return bio_sectors(bio); - + if (no_split) { + val = -1; + } else if (wrt) { val = min_not_zero(READ_ONCE(max_write_size), DM_CRYPT_DEFAULT_MAX_WRITE_SIZE); } else { @@ -465,10 +458,6 @@ static void crypt_iv_lmk_dtr(struct crypt_config *cc) { struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; - if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm)) - crypto_free_shash(lmk->hash_tfm); - lmk->hash_tfm = NULL; - kfree_sensitive(lmk->seed); lmk->seed = NULL; } @@ -483,11 +472,10 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti, return -EINVAL; } - lmk->hash_tfm = crypto_alloc_shash("md5", 0, - CRYPTO_ALG_ALLOCATES_MEMORY); - if (IS_ERR(lmk->hash_tfm)) { - ti->error = "Error initializing LMK hash"; - return PTR_ERR(lmk->hash_tfm); + if (fips_enabled) { + ti->error = "LMK support is disabled due to FIPS"; + /* ... because it uses MD5. */ + return -EINVAL; } /* No seed in LMK version 2 */ @@ -498,7 +486,6 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti, lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL); if (!lmk->seed) { - crypt_iv_lmk_dtr(cc); ti->error = "Error kmallocing seed storage in LMK"; return -ENOMEM; } @@ -514,7 +501,7 @@ static int crypt_iv_lmk_init(struct crypt_config *cc) /* LMK seed is on the position of LMK_KEYS + 1 key */ if (lmk->seed) memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size), - crypto_shash_digestsize(lmk->hash_tfm)); + MD5_DIGEST_SIZE); return 0; } @@ -529,55 +516,31 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc) return 0; } -static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv, - struct dm_crypt_request *dmreq, - u8 *data) +static void crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq, u8 *data) { struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; - SHASH_DESC_ON_STACK(desc, lmk->hash_tfm); - union { - struct md5_state md5state; - u8 state[CRYPTO_MD5_STATESIZE]; - } u; + struct md5_ctx ctx; __le32 buf[4]; - int i, r; - desc->tfm = lmk->hash_tfm; + md5_init(&ctx); - r = crypto_shash_init(desc); - if (r) - return r; - - if (lmk->seed) { - r = crypto_shash_update(desc, lmk->seed, LMK_SEED_SIZE); - if (r) - return r; - } + if (lmk->seed) + md5_update(&ctx, lmk->seed, LMK_SEED_SIZE); /* Sector is always 512B, block size 16, add data of blocks 1-31 */ - r = crypto_shash_update(desc, data + 16, 16 * 31); - if (r) - return r; + md5_update(&ctx, data + 16, 16 * 31); /* Sector is cropped to 56 bits here */ buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF); buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | 0x80000000); buf[2] = cpu_to_le32(4024); buf[3] = 0; - r = crypto_shash_update(desc, (u8 *)buf, sizeof(buf)); - if (r) - return r; + md5_update(&ctx, (u8 *)buf, sizeof(buf)); /* No MD5 padding here */ - r = crypto_shash_export(desc, &u.md5state); - if (r) - return r; - - for (i = 0; i < MD5_HASH_WORDS; i++) - __cpu_to_le32s(&u.md5state.hash[i]); - memcpy(iv, &u.md5state.hash, cc->iv_size); - - return 0; + cpu_to_le32_array(ctx.state.h, ARRAY_SIZE(ctx.state.h)); + memcpy(iv, ctx.state.h, cc->iv_size); } static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv, @@ -585,17 +548,15 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv, { struct scatterlist *sg; u8 *src; - int r = 0; if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) { sg = crypt_get_sg_data(cc, dmreq->sg_in); src = kmap_local_page(sg_page(sg)); - r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset); + crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset); kunmap_local(src); } else memset(iv, 0, cc->iv_size); - - return r; + return 0; } static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv, @@ -603,21 +564,19 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv, { struct scatterlist *sg; u8 *dst; - int r; if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) return 0; sg = crypt_get_sg_data(cc, dmreq->sg_out); dst = kmap_local_page(sg_page(sg)); - r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset); + crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset); /* Tweak the first block of plaintext sector */ - if (!r) - crypto_xor(dst + sg->offset, iv, cc->iv_size); + crypto_xor(dst + sg->offset, iv, cc->iv_size); kunmap_local(dst); - return r; + return 0; } static void crypt_iv_tcw_dtr(struct crypt_config *cc) @@ -1781,7 +1740,7 @@ static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone) bio_for_each_folio_all(fi, clone) { if (folio_test_large(fi.folio)) { percpu_counter_sub(&cc->n_allocated_pages, - 1 << folio_order(fi.folio)); + folio_nr_pages(fi.folio)); folio_put(fi.folio); } else { mempool_free(&fi.folio->page, &cc->page_pool); @@ -3496,6 +3455,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) struct dm_crypt_io *io; struct crypt_config *cc = ti->private; unsigned max_sectors; + bool no_split; /* * If bio is REQ_PREFLUSH or REQ_OP_DISCARD, just bypass crypt queues. @@ -3513,10 +3473,20 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) /* * Check if bio is too large, split as needed. + * + * For zoned devices, splitting write operations creates the + * risk of deadlocking queue freeze operations with zone write + * plugging BIO work when the reminder of a split BIO is + * issued. So always allow the entire BIO to proceed. */ - max_sectors = get_max_request_sectors(ti, bio); - if (unlikely(bio_sectors(bio) > max_sectors)) + no_split = (ti->emulate_zone_append && op_is_write(bio_op(bio))) || + (bio->bi_opf & REQ_ATOMIC); + max_sectors = get_max_request_sectors(ti, bio, no_split); + if (unlikely(bio_sectors(bio) > max_sectors)) { + if (unlikely(no_split)) + return DM_MAPIO_KILL; dm_accept_partial_bio(bio, max_sectors); + } /* * Ensure that bio is a multiple of internal sector encryption size @@ -3762,15 +3732,20 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits) if (ti->emulate_zone_append) limits->max_hw_sectors = min(limits->max_hw_sectors, BIO_MAX_VECS << PAGE_SECTORS_SHIFT); + + limits->atomic_write_hw_unit_max = min(limits->atomic_write_hw_unit_max, + BIO_MAX_VECS << PAGE_SHIFT); + limits->atomic_write_hw_max = min(limits->atomic_write_hw_max, + BIO_MAX_VECS << PAGE_SHIFT); } static struct target_type crypt_target = { .name = "crypt", - .version = {1, 28, 0}, + .version = {1, 29, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, - .features = DM_TARGET_ZONED_HM, + .features = DM_TARGET_ZONED_HM | DM_TARGET_ATOMIC_WRITES, .report_zones = crypt_report_zones, .map = crypt_map, .status = crypt_status, diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c index 6abb31ca9662..b354e74a670e 100644 --- a/drivers/md/dm-ebs-target.c +++ b/drivers/md/dm-ebs-target.c @@ -103,7 +103,7 @@ static int __ebs_rw_bvec(struct ebs_c *ec, enum req_op op, struct bio_vec *bv, } else { flush_dcache_page(bv->bv_page); memcpy(ba, pa, cur_len); - dm_bufio_mark_partial_buffer_dirty(b, buf_off, buf_off + cur_len); + dm_bufio_mark_buffer_dirty(b); } dm_bufio_release(b); diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index b67976637538..061b4d310813 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h @@ -29,7 +29,7 @@ typedef sector_t chunk_t; * chunk within the device. */ struct dm_exception { - struct hlist_bl_node hash_list; + struct hlist_node hash_list; chunk_t old_chunk; chunk_t new_chunk; diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index 7bb7174f8f4f..f0c84e7a5daa 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -432,6 +432,7 @@ static int log_writes_kthread(void *arg) struct log_writes_c *lc = arg; sector_t sector = 0; + set_freezable(); while (!kthread_should_stop()) { bool super = false; bool logging_enabled; diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index aaf4a0a4b0eb..d5d6ef7ba838 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -131,7 +131,7 @@ static void queue_if_no_path_timeout_work(struct timer_list *t); #define MPATHF_QUEUE_IO 0 /* Must we queue all I/O? */ #define MPATHF_QUEUE_IF_NO_PATH 1 /* Queue I/O if last path fails? */ #define MPATHF_SAVED_QUEUE_IF_NO_PATH 2 /* Saved state during suspension */ -#define MPATHF_RETAIN_ATTACHED_HW_HANDLER 3 /* If there's already a hw_handler present, don't change it. */ +/* MPATHF_RETAIN_ATTACHED_HW_HANDLER no longer has any effect */ #define MPATHF_PG_INIT_DISABLED 4 /* pg_init is not currently allowed */ #define MPATHF_PG_INIT_REQUIRED 5 /* pg_init needs calling? */ #define MPATHF_PG_INIT_DELAY_RETRY 6 /* Delay pg_init retry? */ @@ -237,16 +237,10 @@ static struct multipath *alloc_multipath(struct dm_target *ti) static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) { - if (m->queue_mode == DM_TYPE_NONE) { + if (m->queue_mode == DM_TYPE_NONE) m->queue_mode = DM_TYPE_REQUEST_BASED; - } else if (m->queue_mode == DM_TYPE_BIO_BASED) { + else if (m->queue_mode == DM_TYPE_BIO_BASED) INIT_WORK(&m->process_queued_bios, process_queued_bios); - /* - * bio-based doesn't support any direct scsi_dh management; - * it just discovers if a scsi_dh is attached. - */ - set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); - } dm_table_set_type(ti->table, m->queue_mode); @@ -887,36 +881,30 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m, struct request_queue *q = bdev_get_queue(bdev); int r; - if (mpath_double_check_test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, m)) { -retain: - if (*attached_handler_name) { - /* - * Clear any hw_handler_params associated with a - * handler that isn't already attached. - */ - if (m->hw_handler_name && strcmp(*attached_handler_name, m->hw_handler_name)) { - kfree(m->hw_handler_params); - m->hw_handler_params = NULL; - } - - /* - * Reset hw_handler_name to match the attached handler - * - * NB. This modifies the table line to show the actual - * handler instead of the original table passed in. - */ - kfree(m->hw_handler_name); - m->hw_handler_name = *attached_handler_name; - *attached_handler_name = NULL; + if (*attached_handler_name) { + /* + * Clear any hw_handler_params associated with a + * handler that isn't already attached. + */ + if (m->hw_handler_name && strcmp(*attached_handler_name, + m->hw_handler_name)) { + kfree(m->hw_handler_params); + m->hw_handler_params = NULL; } + + /* + * Reset hw_handler_name to match the attached handler + * + * NB. This modifies the table line to show the actual + * handler instead of the original table passed in. + */ + kfree(m->hw_handler_name); + m->hw_handler_name = *attached_handler_name; + *attached_handler_name = NULL; } if (m->hw_handler_name) { r = scsi_dh_attach(q, m->hw_handler_name); - if (r == -EBUSY) { - DMINFO("retaining handler on device %pg", bdev); - goto retain; - } if (r < 0) { *error = "error attaching hardware handler"; return r; @@ -962,6 +950,19 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps q = bdev_get_queue(p->path.dev->bdev); attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL); + if (IS_ERR(attached_handler_name)) { + if (PTR_ERR(attached_handler_name) == -ENODEV) { + if (m->hw_handler_name) { + DMERR("hardware handlers are only allowed for SCSI devices"); + kfree(m->hw_handler_name); + m->hw_handler_name = NULL; + } + attached_handler_name = NULL; + } else { + r = PTR_ERR(attached_handler_name); + goto bad; + } + } if (attached_handler_name || m->hw_handler_name) { INIT_DELAYED_WORK(&p->activate_path, activate_path_work); r = setup_scsi_dh(p->path.dev->bdev, m, &attached_handler_name, &ti->error); @@ -1138,7 +1139,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) } if (!strcasecmp(arg_name, "retain_attached_hw_handler")) { - set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); + /* no longer has any effect */ continue; } @@ -1823,7 +1824,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type, DMEMIT("%u ", test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) + (m->pg_init_retries > 0) * 2 + (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 + - test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags) + (m->queue_mode != DM_TYPE_REQUEST_BASED) * 2); if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) @@ -1832,8 +1832,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type, DMEMIT("pg_init_retries %u ", m->pg_init_retries); if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); - if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) - DMEMIT("retain_attached_hw_handler "); if (m->queue_mode != DM_TYPE_REQUEST_BASED) { switch (m->queue_mode) { case DM_TYPE_BIO_BASED: @@ -2307,7 +2305,7 @@ static struct target_type multipath_target = { .name = "multipath", .version = {1, 15, 0}, .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE | - DM_TARGET_PASSES_INTEGRITY, + DM_TARGET_PASSES_INTEGRITY | DM_TARGET_ATOMIC_WRITES, .module = THIS_MODULE, .ctr = multipath_ctr, .dtr = multipath_dtr, diff --git a/drivers/md/dm-pcache/cache.c b/drivers/md/dm-pcache/cache.c index 698697a7a73c..534bf07b794f 100644 --- a/drivers/md/dm-pcache/cache.c +++ b/drivers/md/dm-pcache/cache.c @@ -10,7 +10,8 @@ struct kmem_cache *key_cache; static inline struct pcache_cache_info *get_cache_info_addr(struct pcache_cache *cache) { - return cache->cache_info_addr + cache->info_index; + return (struct pcache_cache_info *)((char *)cache->cache_info_addr + + (size_t)cache->info_index * PCACHE_CACHE_INFO_SIZE); } static void cache_info_write(struct pcache_cache *cache) @@ -21,10 +22,10 @@ static void cache_info_write(struct pcache_cache *cache) cache_info->header.crc = pcache_meta_crc(&cache_info->header, sizeof(struct pcache_cache_info)); + cache->info_index = (cache->info_index + 1) % PCACHE_META_INDEX_MAX; memcpy_flushcache(get_cache_info_addr(cache), cache_info, sizeof(struct pcache_cache_info)); - - cache->info_index = (cache->info_index + 1) % PCACHE_META_INDEX_MAX; + pmem_wmb(); } static void cache_info_init_default(struct pcache_cache *cache); @@ -49,6 +50,8 @@ static int cache_info_init(struct pcache_cache *cache, struct pcache_cache_optio return -EINVAL; } + cache->info_index = ((char *)cache_info_addr - (char *)cache->cache_info_addr) / PCACHE_CACHE_INFO_SIZE; + return 0; } @@ -93,10 +96,10 @@ void cache_pos_encode(struct pcache_cache *cache, pos_onmedia.header.seq = seq; pos_onmedia.header.crc = cache_pos_onmedia_crc(&pos_onmedia); + *index = (*index + 1) % PCACHE_META_INDEX_MAX; + memcpy_flushcache(pos_onmedia_addr, &pos_onmedia, sizeof(struct pcache_cache_pos_onmedia)); pmem_wmb(); - - *index = (*index + 1) % PCACHE_META_INDEX_MAX; } int cache_pos_decode(struct pcache_cache *cache, diff --git a/drivers/md/dm-pcache/cache_segment.c b/drivers/md/dm-pcache/cache_segment.c index f0b58980806e..9d92e2b067ed 100644 --- a/drivers/md/dm-pcache/cache_segment.c +++ b/drivers/md/dm-pcache/cache_segment.c @@ -26,11 +26,11 @@ static void cache_seg_info_write(struct pcache_cache_segment *cache_seg) seg_info->header.seq++; seg_info->header.crc = pcache_meta_crc(&seg_info->header, sizeof(struct pcache_segment_info)); + cache_seg->info_index = (cache_seg->info_index + 1) % PCACHE_META_INDEX_MAX; + seg_info_addr = get_seg_info_addr(cache_seg); memcpy_flushcache(seg_info_addr, seg_info, sizeof(struct pcache_segment_info)); pmem_wmb(); - - cache_seg->info_index = (cache_seg->info_index + 1) % PCACHE_META_INDEX_MAX; mutex_unlock(&cache_seg->info_lock); } @@ -56,7 +56,10 @@ static int cache_seg_info_load(struct pcache_cache_segment *cache_seg) ret = -EIO; goto out; } - cache_seg->info_index = cache_seg_info_addr - cache_seg_info_addr_base; + + cache_seg->info_index = + ((char *)cache_seg_info_addr - (char *)cache_seg_info_addr_base) / + PCACHE_SEG_INFO_SIZE; out: mutex_unlock(&cache_seg->info_lock); @@ -129,10 +132,10 @@ static void cache_seg_ctrl_write(struct pcache_cache_segment *cache_seg) cache_seg_gen.header.crc = pcache_meta_crc(&cache_seg_gen.header, sizeof(struct pcache_cache_seg_gen)); + cache_seg->gen_index = (cache_seg->gen_index + 1) % PCACHE_META_INDEX_MAX; + memcpy_flushcache(get_cache_seg_gen_addr(cache_seg), &cache_seg_gen, sizeof(struct pcache_cache_seg_gen)); pmem_wmb(); - - cache_seg->gen_index = (cache_seg->gen_index + 1) % PCACHE_META_INDEX_MAX; } static void cache_seg_ctrl_init(struct pcache_cache_segment *cache_seg) diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index c6f7129e43d3..4bacdc499984 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -2287,6 +2287,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) mddev->reshape_position = le64_to_cpu(sb->reshape_position); rs->raid_type = get_raid_type_by_ll(mddev->level, mddev->layout); + if (!rs->raid_type) + return -EINVAL; } } else { diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index f40c18da4000..dbd148967de4 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -40,10 +40,15 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge"; #define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \ (DM_TRACKED_CHUNK_HASH_SIZE - 1)) +struct dm_hlist_head { + struct hlist_head head; + spinlock_t lock; +}; + struct dm_exception_table { uint32_t hash_mask; unsigned int hash_shift; - struct hlist_bl_head *table; + struct dm_hlist_head *table; }; struct dm_snapshot { @@ -628,8 +633,8 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk); /* Lock to protect access to the completed and pending exception hash tables. */ struct dm_exception_table_lock { - struct hlist_bl_head *complete_slot; - struct hlist_bl_head *pending_slot; + spinlock_t *complete_slot; + spinlock_t *pending_slot; }; static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk, @@ -638,20 +643,20 @@ static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk, struct dm_exception_table *complete = &s->complete; struct dm_exception_table *pending = &s->pending; - lock->complete_slot = &complete->table[exception_hash(complete, chunk)]; - lock->pending_slot = &pending->table[exception_hash(pending, chunk)]; + lock->complete_slot = &complete->table[exception_hash(complete, chunk)].lock; + lock->pending_slot = &pending->table[exception_hash(pending, chunk)].lock; } static void dm_exception_table_lock(struct dm_exception_table_lock *lock) { - hlist_bl_lock(lock->complete_slot); - hlist_bl_lock(lock->pending_slot); + spin_lock_nested(lock->complete_slot, 1); + spin_lock_nested(lock->pending_slot, 2); } static void dm_exception_table_unlock(struct dm_exception_table_lock *lock) { - hlist_bl_unlock(lock->pending_slot); - hlist_bl_unlock(lock->complete_slot); + spin_unlock(lock->pending_slot); + spin_unlock(lock->complete_slot); } static int dm_exception_table_init(struct dm_exception_table *et, @@ -661,13 +666,15 @@ static int dm_exception_table_init(struct dm_exception_table *et, et->hash_shift = hash_shift; et->hash_mask = size - 1; - et->table = kvmalloc_array(size, sizeof(struct hlist_bl_head), + et->table = kvmalloc_array(size, sizeof(struct dm_hlist_head), GFP_KERNEL); if (!et->table) return -ENOMEM; - for (i = 0; i < size; i++) - INIT_HLIST_BL_HEAD(et->table + i); + for (i = 0; i < size; i++) { + INIT_HLIST_HEAD(&et->table[i].head); + spin_lock_init(&et->table[i].lock); + } return 0; } @@ -675,16 +682,17 @@ static int dm_exception_table_init(struct dm_exception_table *et, static void dm_exception_table_exit(struct dm_exception_table *et, struct kmem_cache *mem) { - struct hlist_bl_head *slot; + struct dm_hlist_head *slot; struct dm_exception *ex; - struct hlist_bl_node *pos, *n; + struct hlist_node *pos; int i, size; size = et->hash_mask + 1; for (i = 0; i < size; i++) { slot = et->table + i; - hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list) { + hlist_for_each_entry_safe(ex, pos, &slot->head, hash_list) { + hlist_del(&ex->hash_list); kmem_cache_free(mem, ex); cond_resched(); } @@ -700,7 +708,7 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk) static void dm_remove_exception(struct dm_exception *e) { - hlist_bl_del(&e->hash_list); + hlist_del(&e->hash_list); } /* @@ -710,12 +718,11 @@ static void dm_remove_exception(struct dm_exception *e) static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et, chunk_t chunk) { - struct hlist_bl_head *slot; - struct hlist_bl_node *pos; + struct hlist_head *slot; struct dm_exception *e; - slot = &et->table[exception_hash(et, chunk)]; - hlist_bl_for_each_entry(e, pos, slot, hash_list) + slot = &et->table[exception_hash(et, chunk)].head; + hlist_for_each_entry(e, slot, hash_list) if (chunk >= e->old_chunk && chunk <= e->old_chunk + dm_consecutive_chunk_count(e)) return e; @@ -762,18 +769,17 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe) static void dm_insert_exception(struct dm_exception_table *eh, struct dm_exception *new_e) { - struct hlist_bl_head *l; - struct hlist_bl_node *pos; + struct hlist_head *l; struct dm_exception *e = NULL; - l = &eh->table[exception_hash(eh, new_e->old_chunk)]; + l = &eh->table[exception_hash(eh, new_e->old_chunk)].head; /* Add immediately if this table doesn't support consecutive chunks */ if (!eh->hash_shift) goto out; /* List is ordered by old_chunk */ - hlist_bl_for_each_entry(e, pos, l, hash_list) { + hlist_for_each_entry(e, l, hash_list) { /* Insert after an existing chunk? */ if (new_e->old_chunk == (e->old_chunk + dm_consecutive_chunk_count(e) + 1) && @@ -804,13 +810,13 @@ out: * Either the table doesn't support consecutive chunks or slot * l is empty. */ - hlist_bl_add_head(&new_e->hash_list, l); + hlist_add_head(&new_e->hash_list, l); } else if (new_e->old_chunk < e->old_chunk) { /* Add before an existing exception */ - hlist_bl_add_before(&new_e->hash_list, &e->hash_list); + hlist_add_before(&new_e->hash_list, &e->hash_list); } else { /* Add to l's tail: e is the last exception in this slot */ - hlist_bl_add_behind(&new_e->hash_list, &e->hash_list); + hlist_add_behind(&new_e->hash_list, &e->hash_list); } } @@ -820,7 +826,6 @@ out: */ static int dm_add_exception(void *context, chunk_t old, chunk_t new) { - struct dm_exception_table_lock lock; struct dm_snapshot *s = context; struct dm_exception *e; @@ -833,17 +838,7 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new) /* Consecutive_count is implicitly initialised to zero */ e->new_chunk = new; - /* - * Although there is no need to lock access to the exception tables - * here, if we don't then hlist_bl_add_head(), called by - * dm_insert_exception(), will complain about accessing the - * corresponding list without locking it first. - */ - dm_exception_table_lock_init(s, old, &lock); - - dm_exception_table_lock(&lock); dm_insert_exception(&s->complete, e); - dm_exception_table_unlock(&lock); return 0; } @@ -873,7 +868,7 @@ static int calc_max_buckets(void) /* use a fixed size of 2MB */ unsigned long mem = 2 * 1024 * 1024; - mem /= sizeof(struct hlist_bl_head); + mem /= sizeof(struct dm_hlist_head); return mem; } diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index bfaef27ca79f..22bc70923a83 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c @@ -86,17 +86,13 @@ static ssize_t dm_attr_uuid_show(struct mapped_device *md, char *buf) static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf) { - sprintf(buf, "%d\n", dm_suspended_md(md)); - - return strlen(buf); + return sysfs_emit(buf, "%d\n", dm_suspended_md(md)); } static ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf) { /* Purely for userspace compatibility */ - sprintf(buf, "%d\n", true); - - return strlen(buf); + return sysfs_emit(buf, "%d\n", true); } static DM_ATTR_RO(name); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index ad0a60a07b93..0522cd700e0e 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -2043,6 +2043,10 @@ bool dm_table_supports_size_change(struct dm_table *t, sector_t old_size, return true; } +/* + * This function will be skipped by noflush reloads of immutable request + * based devices (dm-mpath). + */ int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, struct queue_limits *limits) { diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index c84149ba4e38..52ffb495f5a8 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -395,13 +395,13 @@ static void begin_discard(struct discard_op *op, struct thin_c *tc, struct bio * op->bio = NULL; } -static int issue_discard(struct discard_op *op, dm_block_t data_b, dm_block_t data_e) +static void issue_discard(struct discard_op *op, dm_block_t data_b, dm_block_t data_e) { struct thin_c *tc = op->tc; sector_t s = block_to_sectors(tc->pool, data_b); sector_t len = block_to_sectors(tc->pool, data_e - data_b); - return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOIO, &op->bio); + __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOIO, &op->bio); } static void end_discard(struct discard_op *op, int r) @@ -1113,9 +1113,7 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m break; } - r = issue_discard(&op, b, e); - if (r) - goto out; + issue_discard(&op, b, e); b = e; } @@ -1188,8 +1186,8 @@ static void process_prepared_discard_passdown_pt1(struct dm_thin_new_mapping *m) struct discard_op op; begin_discard(&op, tc, discard_parent); - r = issue_discard(&op, m->data_block, data_end); - end_discard(&op, r); + issue_discard(&op, m->data_block, data_end); + end_discard(&op, 0); } } @@ -4383,11 +4381,8 @@ static void thin_postsuspend(struct dm_target *ti) { struct thin_c *tc = ti->private; - /* - * The dm_noflush_suspending flag has been cleared by now, so - * unfortunately we must always run this. - */ - noflush_work(tc, do_noflush_stop); + if (dm_noflush_suspending(ti)) + noflush_work(tc, do_noflush_stop); } static int thin_preresume(struct dm_target *ti) diff --git a/drivers/md/dm-vdo/action-manager.c b/drivers/md/dm-vdo/action-manager.c index a0e5e7077d13..e3bba0b28aad 100644 --- a/drivers/md/dm-vdo/action-manager.c +++ b/drivers/md/dm-vdo/action-manager.c @@ -43,7 +43,7 @@ struct action { * @actions: The two action slots. * @current_action: The current action slot. * @zones: The number of zones in which an action is to be applied. - * @Scheduler: A function to schedule a default next action. + * @scheduler: A function to schedule a default next action. * @get_zone_thread_id: A function to get the id of the thread on which to apply an action to a * zone. * @initiator_thread_id: The ID of the thread on which actions may be initiated. diff --git a/drivers/md/dm-vdo/admin-state.c b/drivers/md/dm-vdo/admin-state.c index 3f9dba525154..da153fef085e 100644 --- a/drivers/md/dm-vdo/admin-state.c +++ b/drivers/md/dm-vdo/admin-state.c @@ -149,7 +149,8 @@ const struct admin_state_code *VDO_ADMIN_STATE_RESUMING = &VDO_CODE_RESUMING; /** * get_next_state() - Determine the state which should be set after a given operation completes * based on the operation and the current state. - * @operation The operation to be started. + * @state: The current admin state. + * @operation: The operation to be started. * * Return: The state to set when the operation completes or NULL if the operation can not be * started in the current state. @@ -187,6 +188,8 @@ static const struct admin_state_code *get_next_state(const struct admin_state *s /** * vdo_finish_operation() - Finish the current operation. + * @state: The current admin state. + * @result: The result of the operation. * * Will notify the operation waiter if there is one. This method should be used for operations * started with vdo_start_operation(). For operations which were started with vdo_start_draining(), @@ -214,8 +217,10 @@ bool vdo_finish_operation(struct admin_state *state, int result) /** * begin_operation() - Begin an operation if it may be started given the current state. - * @waiter A completion to notify when the operation is complete; may be NULL. - * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. + * @state: The current admin state. + * @operation: The operation to be started. + * @waiter: A completion to notify when the operation is complete; may be NULL. + * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. * * Return: VDO_SUCCESS or an error. */ @@ -259,8 +264,10 @@ static int __must_check begin_operation(struct admin_state *state, /** * start_operation() - Start an operation if it may be started given the current state. - * @waiter A completion to notify when the operation is complete. - * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. + * @state: The current admin state. + * @operation: The operation to be started. + * @waiter: A completion to notify when the operation is complete; may be NULL. + * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. * * Return: true if the operation was started. */ @@ -274,10 +281,10 @@ static inline bool __must_check start_operation(struct admin_state *state, /** * check_code() - Check the result of a state validation. - * @valid true if the code is of an appropriate type. - * @code The code which failed to be of the correct type. - * @what What the code failed to be, for logging. - * @waiter The completion to notify of the error; may be NULL. + * @valid: True if the code is of an appropriate type. + * @code: The code which failed to be of the correct type. + * @what: What the code failed to be, for logging. + * @waiter: The completion to notify of the error; may be NULL. * * If the result failed, log an invalid state error and, if there is a waiter, notify it. * @@ -301,7 +308,8 @@ static bool check_code(bool valid, const struct admin_state_code *code, const ch /** * assert_vdo_drain_operation() - Check that an operation is a drain. - * @waiter The completion to finish with an error if the operation is not a drain. + * @operation: The operation to check. + * @waiter: The completion to finish with an error if the operation is not a drain. * * Return: true if the specified operation is a drain. */ @@ -313,9 +321,10 @@ static bool __must_check assert_vdo_drain_operation(const struct admin_state_cod /** * vdo_start_draining() - Initiate a drain operation if the current state permits it. - * @operation The type of drain to initiate. - * @waiter The completion to notify when the drain is complete. - * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. + * @state: The current admin state. + * @operation: The type of drain to initiate. + * @waiter: The completion to notify when the drain is complete. + * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. * * Return: true if the drain was initiated, if not the waiter will be notified. */ @@ -345,6 +354,7 @@ bool vdo_start_draining(struct admin_state *state, /** * vdo_finish_draining() - Finish a drain operation if one was in progress. + * @state: The current admin state. * * Return: true if the state was draining; will notify the waiter if so. */ @@ -355,6 +365,8 @@ bool vdo_finish_draining(struct admin_state *state) /** * vdo_finish_draining_with_result() - Finish a drain operation with a status code. + * @state: The current admin state. + * @result: The result of the drain operation. * * Return: true if the state was draining; will notify the waiter if so. */ @@ -365,7 +377,8 @@ bool vdo_finish_draining_with_result(struct admin_state *state, int result) /** * vdo_assert_load_operation() - Check that an operation is a load. - * @waiter The completion to finish with an error if the operation is not a load. + * @operation: The operation to check. + * @waiter: The completion to finish with an error if the operation is not a load. * * Return: true if the specified operation is a load. */ @@ -377,9 +390,10 @@ bool vdo_assert_load_operation(const struct admin_state_code *operation, /** * vdo_start_loading() - Initiate a load operation if the current state permits it. - * @operation The type of load to initiate. - * @waiter The completion to notify when the load is complete (may be NULL). - * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. + * @state: The current admin state. + * @operation: The type of load to initiate. + * @waiter: The completion to notify when the load is complete; may be NULL. + * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. * * Return: true if the load was initiated, if not the waiter will be notified. */ @@ -393,6 +407,7 @@ bool vdo_start_loading(struct admin_state *state, /** * vdo_finish_loading() - Finish a load operation if one was in progress. + * @state: The current admin state. * * Return: true if the state was loading; will notify the waiter if so. */ @@ -403,7 +418,8 @@ bool vdo_finish_loading(struct admin_state *state) /** * vdo_finish_loading_with_result() - Finish a load operation with a status code. - * @result The result of the load operation. + * @state: The current admin state. + * @result: The result of the load operation. * * Return: true if the state was loading; will notify the waiter if so. */ @@ -414,7 +430,8 @@ bool vdo_finish_loading_with_result(struct admin_state *state, int result) /** * assert_vdo_resume_operation() - Check whether an admin_state_code is a resume operation. - * @waiter The completion to notify if the operation is not a resume operation; may be NULL. + * @operation: The operation to check. + * @waiter: The completion to notify if the operation is not a resume operation; may be NULL. * * Return: true if the code is a resume operation. */ @@ -427,9 +444,10 @@ static bool __must_check assert_vdo_resume_operation(const struct admin_state_co /** * vdo_start_resuming() - Initiate a resume operation if the current state permits it. - * @operation The type of resume to start. - * @waiter The completion to notify when the resume is complete (may be NULL). - * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. + * @state: The current admin state. + * @operation: The type of resume to start. + * @waiter: The completion to notify when the resume is complete; may be NULL. + * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. * * Return: true if the resume was initiated, if not the waiter will be notified. */ @@ -443,6 +461,7 @@ bool vdo_start_resuming(struct admin_state *state, /** * vdo_finish_resuming() - Finish a resume operation if one was in progress. + * @state: The current admin state. * * Return: true if the state was resuming; will notify the waiter if so. */ @@ -453,7 +472,8 @@ bool vdo_finish_resuming(struct admin_state *state) /** * vdo_finish_resuming_with_result() - Finish a resume operation with a status code. - * @result The result of the resume operation. + * @state: The current admin state. + * @result: The result of the resume operation. * * Return: true if the state was resuming; will notify the waiter if so. */ @@ -465,6 +485,7 @@ bool vdo_finish_resuming_with_result(struct admin_state *state, int result) /** * vdo_resume_if_quiescent() - Change the state to normal operation if the current state is * quiescent. + * @state: The current admin state. * * Return: VDO_SUCCESS if the state resumed, VDO_INVALID_ADMIN_STATE otherwise. */ @@ -479,6 +500,8 @@ int vdo_resume_if_quiescent(struct admin_state *state) /** * vdo_start_operation() - Attempt to start an operation. + * @state: The current admin state. + * @operation: The operation to attempt to start. * * Return: VDO_SUCCESS if the operation was started, VDO_INVALID_ADMIN_STATE if not */ @@ -490,8 +513,10 @@ int vdo_start_operation(struct admin_state *state, /** * vdo_start_operation_with_waiter() - Attempt to start an operation. - * @waiter the completion to notify when the operation completes or fails to start; may be NULL. - * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. + * @state: The current admin state. + * @operation: The operation to attempt to start. + * @waiter: The completion to notify when the operation completes or fails to start; may be NULL. + * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL. * * Return: VDO_SUCCESS if the operation was started, VDO_INVALID_ADMIN_STATE if not */ diff --git a/drivers/md/dm-vdo/block-map.c b/drivers/md/dm-vdo/block-map.c index baf683cabb1b..a7db5b41155e 100644 --- a/drivers/md/dm-vdo/block-map.c +++ b/drivers/md/dm-vdo/block-map.c @@ -174,6 +174,7 @@ static inline struct vdo_page_completion *page_completion_from_waiter(struct vdo /** * initialize_info() - Initialize all page info structures and put them on the free list. + * @cache: The page cache. * * Return: VDO_SUCCESS or an error. */ @@ -209,6 +210,7 @@ static int initialize_info(struct vdo_page_cache *cache) /** * allocate_cache_components() - Allocate components of the cache which require their own * allocation. + * @cache: The page cache. * * The caller is responsible for all clean up on errors. * @@ -238,6 +240,8 @@ static int __must_check allocate_cache_components(struct vdo_page_cache *cache) /** * assert_on_cache_thread() - Assert that a function has been called on the VDO page cache's * thread. + * @cache: The page cache. + * @function_name: The funtion name to report if the assertion fails. */ static inline void assert_on_cache_thread(struct vdo_page_cache *cache, const char *function_name) @@ -271,6 +275,7 @@ static void report_cache_pressure(struct vdo_page_cache *cache) /** * get_page_state_name() - Return the name of a page state. + * @state: The page state to describe. * * If the page state is invalid a static string is returned and the invalid state is logged. * @@ -342,6 +347,8 @@ static void update_lru(struct page_info *info) /** * set_info_state() - Set the state of a page_info and put it on the right list, adjusting * counters. + * @info: The page info to update. + * @new_state: The new state to set. */ static void set_info_state(struct page_info *info, enum vdo_page_buffer_state new_state) { @@ -416,6 +423,7 @@ static int reset_page_info(struct page_info *info) /** * find_free_page() - Find a free page. + * @cache: The page cache. * * Return: A pointer to the page info structure (if found), NULL otherwise. */ @@ -433,6 +441,7 @@ static struct page_info * __must_check find_free_page(struct vdo_page_cache *cac /** * find_page() - Find the page info (if any) associated with a given pbn. + * @cache: The page cache. * @pbn: The absolute physical block number of the page. * * Return: The page info for the page if available, or NULL if not. @@ -449,6 +458,7 @@ static struct page_info * __must_check find_page(struct vdo_page_cache *cache, /** * select_lru_page() - Determine which page is least recently used. + * @cache: The page cache. * * Picks the least recently used from among the non-busy entries at the front of each of the lru * list. Since whenever we mark a page busy we also put it to the end of the list it is unlikely @@ -523,6 +533,8 @@ static void complete_waiter_with_page(struct vdo_waiter *waiter, void *page_info /** * distribute_page_over_waitq() - Complete a waitq of VDO page completions with a page result. + * @info: The loaded page info. + * @waitq: The list of waiting data_vios. * * Upon completion the waitq will be empty. * @@ -548,7 +560,9 @@ static unsigned int distribute_page_over_waitq(struct page_info *info, /** * set_persistent_error() - Set a persistent error which all requests will receive in the future. + * @cache: The page cache. * @context: A string describing what triggered the error. + * @result: The error result to set on the cache. * * Once triggered, all enqueued completions will get this error. Any future requests will result in * this error as well. @@ -581,6 +595,7 @@ static void set_persistent_error(struct vdo_page_cache *cache, const char *conte /** * validate_completed_page() - Check that a page completion which is being freed to the cache * referred to a valid page and is in a valid state. + * @completion: The page completion to check. * @writable: Whether a writable page is required. * * Return: VDO_SUCCESS if the page was valid, otherwise as error @@ -758,6 +773,8 @@ static void load_cache_page_endio(struct bio *bio) /** * launch_page_load() - Begin the process of loading a page. + * @info: The page info to launch. + * @pbn: The absolute physical block number of the page to load. * * Return: VDO_SUCCESS or an error code. */ @@ -836,6 +853,7 @@ static void save_pages(struct vdo_page_cache *cache) /** * schedule_page_save() - Add a page to the outgoing list of pages waiting to be saved. + * @info: The page info to save. * * Once in the list, a page may not be used until it has been written out. */ @@ -854,6 +872,7 @@ static void schedule_page_save(struct page_info *info) /** * launch_page_save() - Add a page to outgoing pages waiting to be saved, and then start saving * pages if another save is not in progress. + * @info: The page info to save. */ static void launch_page_save(struct page_info *info) { @@ -864,6 +883,7 @@ static void launch_page_save(struct page_info *info) /** * completion_needs_page() - Determine whether a given vdo_page_completion (as a waiter) is * requesting a given page number. + * @waiter: The page completion waiter to check. * @context: A pointer to the pbn of the desired page. * * Implements waiter_match_fn. @@ -880,6 +900,7 @@ static bool completion_needs_page(struct vdo_waiter *waiter, void *context) /** * allocate_free_page() - Allocate a free page to the first completion in the waiting queue, and * any other completions that match it in page number. + * @info: The page info to allocate a page for. */ static void allocate_free_page(struct page_info *info) { @@ -925,6 +946,7 @@ static void allocate_free_page(struct page_info *info) /** * discard_a_page() - Begin the process of discarding a page. + * @cache: The page cache. * * If no page is discardable, increments a count of deferred frees so that the next release of a * page which is no longer busy will kick off another discard cycle. This is an indication that the @@ -955,10 +977,6 @@ static void discard_a_page(struct vdo_page_cache *cache) launch_page_save(info); } -/** - * discard_page_for_completion() - Helper used to trigger a discard so that the completion can get - * a different page. - */ static void discard_page_for_completion(struct vdo_page_completion *vdo_page_comp) { struct vdo_page_cache *cache = vdo_page_comp->cache; @@ -1132,6 +1150,7 @@ static void write_pages(struct vdo_completion *flush_completion) /** * vdo_release_page_completion() - Release a VDO Page Completion. + * @completion: The page completion to release. * * The page referenced by this completion (if any) will no longer be held busy by this completion. * If a page becomes discardable and there are completions awaiting free pages then a new round of @@ -1172,10 +1191,6 @@ void vdo_release_page_completion(struct vdo_completion *completion) } } -/** - * load_page_for_completion() - Helper function to load a page as described by a VDO Page - * Completion. - */ static void load_page_for_completion(struct page_info *info, struct vdo_page_completion *vdo_page_comp) { @@ -1319,6 +1334,7 @@ int vdo_get_cached_page(struct vdo_completion *completion, /** * vdo_invalidate_page_cache() - Invalidate all entries in the VDO page cache. + * @cache: The page cache. * * There must not be any dirty pages in the cache. * @@ -1345,6 +1361,10 @@ int vdo_invalidate_page_cache(struct vdo_page_cache *cache) /** * get_tree_page_by_index() - Get the tree page for a given height and page index. + * @forest: The block map forest. + * @root_index: The root index of the tree to search. + * @height: The height in the tree. + * @page_index: The page index. * * Return: The requested page. */ @@ -2211,6 +2231,7 @@ static void allocate_block_map_page(struct block_map_zone *zone, /** * vdo_find_block_map_slot() - Find the block map slot in which the block map entry for a data_vio * resides and cache that result in the data_vio. + * @data_vio: The data vio. * * All ancestors in the tree will be allocated or loaded, as needed. */ @@ -2435,6 +2456,7 @@ static void deforest(struct forest *forest, size_t first_page_segment) /** * make_forest() - Make a collection of trees for a block_map, expanding the existing forest if * there is one. + * @map: The block map. * @entries: The number of entries the block map will hold. * * Return: VDO_SUCCESS or an error. @@ -2476,6 +2498,7 @@ static int make_forest(struct block_map *map, block_count_t entries) /** * replace_forest() - Replace a block_map's forest with the already-prepared larger forest. + * @map: The block map. */ static void replace_forest(struct block_map *map) { @@ -2492,6 +2515,7 @@ static void replace_forest(struct block_map *map) /** * finish_cursor() - Finish the traversal of a single tree. If it was the last cursor, finish the * traversal. + * @cursor: The cursor to complete. */ static void finish_cursor(struct cursor *cursor) { @@ -2549,6 +2573,7 @@ static void traversal_endio(struct bio *bio) /** * traverse() - Traverse a single block map tree. + * @cursor: A cursor tracking traversal progress. * * This is the recursive heart of the traversal process. */ @@ -2619,6 +2644,7 @@ static void traverse(struct cursor *cursor) /** * launch_cursor() - Start traversing a single block map tree now that the cursor has a VIO with * which to load pages. + * @waiter: The parent of the cursor to launch. * @context: The pooled_vio just acquired. * * Implements waiter_callback_fn. @@ -2636,6 +2662,8 @@ static void launch_cursor(struct vdo_waiter *waiter, void *context) /** * compute_boundary() - Compute the number of pages used at each level of the given root's tree. + * @map: The block map. + * @root_index: The tree root index. * * Return: The list of page counts as a boundary structure. */ @@ -2668,6 +2696,7 @@ static struct boundary compute_boundary(struct block_map *map, root_count_t root /** * vdo_traverse_forest() - Walk the entire forest of a block map. + * @map: The block map. * @callback: A function to call with the pbn of each allocated node in the forest. * @completion: The completion to notify on each traversed PBN, and when traversal completes. */ @@ -2707,6 +2736,9 @@ void vdo_traverse_forest(struct block_map *map, vdo_entry_callback_fn callback, /** * initialize_block_map_zone() - Initialize the per-zone portions of the block map. + * @map: The block map. + * @zone_number: The zone to initialize. + * @cache_size: The total block map cache size. * @maximum_age: The number of journal blocks before a dirtied page is considered old and must be * written out. */ @@ -3091,6 +3123,7 @@ static void fetch_mapping_page(struct data_vio *data_vio, bool modifiable, /** * clear_mapped_location() - Clear a data_vio's mapped block location, setting it to be unmapped. + * @data_vio: The data vio. * * This indicates the block map entry for the logical block is either unmapped or corrupted. */ @@ -3104,6 +3137,8 @@ static void clear_mapped_location(struct data_vio *data_vio) /** * set_mapped_location() - Decode and validate a block map entry, and set the mapped location of a * data_vio. + * @data_vio: The data vio. + * @entry: The new mapped entry to set. * * Return: VDO_SUCCESS or VDO_BAD_MAPPING if the map entry is invalid or an error code for any * other failure diff --git a/drivers/md/dm-vdo/completion.c b/drivers/md/dm-vdo/completion.c index 5ad85334632d..2f00acbb3b2b 100644 --- a/drivers/md/dm-vdo/completion.c +++ b/drivers/md/dm-vdo/completion.c @@ -65,6 +65,8 @@ static inline void assert_incomplete(struct vdo_completion *completion) /** * vdo_set_completion_result() - Set the result of a completion. + * @completion: The completion to update. + * @result: The result to set. * * Older errors will not be masked. */ @@ -77,6 +79,7 @@ void vdo_set_completion_result(struct vdo_completion *completion, int result) /** * vdo_launch_completion_with_priority() - Run or enqueue a completion. + * @completion: The completion to launch. * @priority: The priority at which to enqueue the completion. * * If called on the correct thread (i.e. the one specified in the completion's callback_thread_id @@ -125,6 +128,8 @@ void vdo_enqueue_completion(struct vdo_completion *completion, /** * vdo_requeue_completion_if_needed() - Requeue a completion if not called on the specified thread. + * @completion: The completion to requeue. + * @callback_thread_id: The thread on which to requeue the completion. * * Return: True if the completion was requeued; callers may not access the completion in this case. */ diff --git a/drivers/md/dm-vdo/data-vio.c b/drivers/md/dm-vdo/data-vio.c index 262e11581f2d..3333e1e5b02e 100644 --- a/drivers/md/dm-vdo/data-vio.c +++ b/drivers/md/dm-vdo/data-vio.c @@ -227,6 +227,7 @@ static inline u64 get_arrival_time(struct bio *bio) /** * check_for_drain_complete_locked() - Check whether a data_vio_pool has no outstanding data_vios * or waiters while holding the pool's lock. + * @pool: The data_vio pool. */ static bool check_for_drain_complete_locked(struct data_vio_pool *pool) { @@ -387,6 +388,7 @@ struct data_vio_compression_status advance_data_vio_compression_stage(struct dat /** * cancel_data_vio_compression() - Prevent this data_vio from being compressed or packed. + * @data_vio: The data_vio. * * Return: true if the data_vio is in the packer and the caller was the first caller to cancel it. */ @@ -483,6 +485,8 @@ static void attempt_logical_block_lock(struct vdo_completion *completion) /** * launch_data_vio() - (Re)initialize a data_vio to have a new logical block number, keeping the * same parent and other state and send it on its way. + * @data_vio: The data_vio to launch. + * @lbn: The logical block number. */ static void launch_data_vio(struct data_vio *data_vio, logical_block_number_t lbn) { @@ -641,6 +645,7 @@ static void update_limiter(struct limiter *limiter) /** * schedule_releases() - Ensure that release processing is scheduled. + * @pool: The data_vio pool. * * If this call switches the state to processing, enqueue. Otherwise, some other thread has already * done so. @@ -768,6 +773,8 @@ static void initialize_limiter(struct limiter *limiter, struct data_vio_pool *po /** * initialize_data_vio() - Allocate the components of a data_vio. + * @data_vio: The data_vio to initialize. + * @vdo: The vdo containing the data_vio. * * The caller is responsible for cleaning up the data_vio on error. * @@ -880,6 +887,7 @@ int make_data_vio_pool(struct vdo *vdo, data_vio_count_t pool_size, /** * free_data_vio_pool() - Free a data_vio_pool and the data_vios in it. + * @pool: The data_vio pool to free. * * All data_vios must be returned to the pool before calling this function. */ @@ -944,6 +952,8 @@ static void wait_permit(struct limiter *limiter, struct bio *bio) /** * vdo_launch_bio() - Acquire a data_vio from the pool, assign the bio to it, and launch it. + * @pool: The data_vio pool. + * @bio: The bio to launch. * * This will block if data_vios or discard permits are not available. */ @@ -994,6 +1004,7 @@ static void assert_on_vdo_cpu_thread(const struct vdo *vdo, const char *name) /** * drain_data_vio_pool() - Wait asynchronously for all data_vios to be returned to the pool. + * @pool: The data_vio pool. * @completion: The completion to notify when the pool has drained. */ void drain_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *completion) @@ -1005,6 +1016,7 @@ void drain_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *comp /** * resume_data_vio_pool() - Resume a data_vio pool. + * @pool: The data_vio pool. * @completion: The completion to notify when the pool has resumed. */ void resume_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *completion) @@ -1024,6 +1036,7 @@ static void dump_limiter(const char *name, struct limiter *limiter) /** * dump_data_vio_pool() - Dump a data_vio pool to the log. + * @pool: The data_vio pool. * @dump_vios: Whether to dump the details of each busy data_vio as well. */ void dump_data_vio_pool(struct data_vio_pool *pool, bool dump_vios) @@ -1114,6 +1127,7 @@ static void perform_cleanup_stage(struct data_vio *data_vio, /** * release_allocated_lock() - Release the PBN lock and/or the reference on the allocated block at * the end of processing a data_vio. + * @completion: The data_vio holding the lock. */ static void release_allocated_lock(struct vdo_completion *completion) { @@ -1194,6 +1208,7 @@ static void transfer_lock(struct data_vio *data_vio, struct lbn_lock *lock) /** * release_logical_lock() - Release the logical block lock and flush generation lock at the end of * processing a data_vio. + * @completion: The data_vio holding the lock. */ static void release_logical_lock(struct vdo_completion *completion) { @@ -1228,6 +1243,7 @@ static void clean_hash_lock(struct vdo_completion *completion) /** * finish_cleanup() - Make some assertions about a data_vio which has finished cleaning up. + * @data_vio: The data_vio. * * If it is part of a multi-block discard, starts on the next block, otherwise, returns it to the * pool. @@ -1342,6 +1358,7 @@ void handle_data_vio_error(struct vdo_completion *completion) /** * get_data_vio_operation_name() - Get the name of the last asynchronous operation performed on a * data_vio. + * @data_vio: The data_vio. */ const char *get_data_vio_operation_name(struct data_vio *data_vio) { @@ -1355,7 +1372,7 @@ const char *get_data_vio_operation_name(struct data_vio *data_vio) /** * data_vio_allocate_data_block() - Allocate a data block. - * + * @data_vio: The data_vio. * @write_lock_type: The type of write lock to obtain on the block. * @callback: The callback which will attempt an allocation in the current zone and continue if it * succeeds. @@ -1379,6 +1396,7 @@ void data_vio_allocate_data_block(struct data_vio *data_vio, /** * release_data_vio_allocation_lock() - Release the PBN lock on a data_vio's allocated block. + * @data_vio: The data_vio. * @reset: If true, the allocation will be reset (i.e. any allocated pbn will be forgotten). * * If the reference to the locked block is still provisional, it will be released as well. @@ -1399,6 +1417,7 @@ void release_data_vio_allocation_lock(struct data_vio *data_vio, bool reset) /** * uncompress_data_vio() - Uncompress the data a data_vio has just read. + * @data_vio: The data_vio. * @mapping_state: The mapping state indicating which fragment to decompress. * @buffer: The buffer to receive the uncompressed data. */ @@ -1519,6 +1538,7 @@ static void complete_zero_read(struct vdo_completion *completion) /** * read_block() - Read a block asynchronously. + * @completion: The data_vio doing the read. * * This is the callback registered in read_block_mapping(). */ @@ -1675,6 +1695,7 @@ static void journal_remapping(struct vdo_completion *completion) /** * read_old_block_mapping() - Get the previous PBN/LBN mapping of an in-progress write. + * @completion: The data_vio doing the read. * * Gets the previous PBN mapped to this LBN from the block map, so as to make an appropriate * journal entry referencing the removal of this LBN->PBN mapping. @@ -1704,6 +1725,7 @@ void update_metadata_for_data_vio_write(struct data_vio *data_vio, struct pbn_lo /** * pack_compressed_data() - Attempt to pack the compressed data_vio into a block. + * @completion: The data_vio. * * This is the callback registered in launch_compress_data_vio(). */ @@ -1725,6 +1747,7 @@ static void pack_compressed_data(struct vdo_completion *completion) /** * compress_data_vio() - Do the actual work of compressing the data on a CPU queue. + * @completion: The data_vio. * * This callback is registered in launch_compress_data_vio(). */ @@ -1754,6 +1777,7 @@ static void compress_data_vio(struct vdo_completion *completion) /** * launch_compress_data_vio() - Continue a write by attempting to compress the data. + * @data_vio: The data_vio. * * This is a re-entry point to vio_write used by hash locks. */ @@ -1796,7 +1820,8 @@ void launch_compress_data_vio(struct data_vio *data_vio) /** * hash_data_vio() - Hash the data in a data_vio and set the hash zone (which also flags the record * name as set). - + * @completion: The data_vio. + * * This callback is registered in prepare_for_dedupe(). */ static void hash_data_vio(struct vdo_completion *completion) @@ -1832,6 +1857,7 @@ static void prepare_for_dedupe(struct data_vio *data_vio) /** * write_bio_finished() - This is the bio_end_io function registered in write_block() to be called * when a data_vio's write to the underlying storage has completed. + * @bio: The bio to update. */ static void write_bio_finished(struct bio *bio) { @@ -1884,6 +1910,7 @@ void write_data_vio(struct data_vio *data_vio) /** * acknowledge_write_callback() - Acknowledge a write to the requestor. + * @completion: The data_vio. * * This callback is registered in allocate_block() and continue_write_with_block_map_slot(). */ @@ -1909,6 +1936,7 @@ static void acknowledge_write_callback(struct vdo_completion *completion) /** * allocate_block() - Attempt to allocate a block in the current allocation zone. + * @completion: The data_vio. * * This callback is registered in continue_write_with_block_map_slot(). */ @@ -1941,6 +1969,7 @@ static void allocate_block(struct vdo_completion *completion) /** * handle_allocation_error() - Handle an error attempting to allocate a block. + * @completion: The data_vio. * * This error handler is registered in continue_write_with_block_map_slot(). */ @@ -1970,6 +1999,7 @@ static int assert_is_discard(struct data_vio *data_vio) /** * continue_data_vio_with_block_map_slot() - Read the data_vio's mapping from the block map. + * @completion: The data_vio to continue. * * This callback is registered in launch_read_data_vio(). */ diff --git a/drivers/md/dm-vdo/dedupe.c b/drivers/md/dm-vdo/dedupe.c index 4d983092a152..75a26f3f4461 100644 --- a/drivers/md/dm-vdo/dedupe.c +++ b/drivers/md/dm-vdo/dedupe.c @@ -917,6 +917,8 @@ static int __must_check acquire_lock(struct hash_zone *zone, /** * enter_forked_lock() - Bind the data_vio to a new hash lock. + * @waiter: The data_vio's waiter link. + * @context: The new hash lock. * * Implements waiter_callback_fn. Binds the data_vio that was waiting to a new hash lock and waits * on that lock. @@ -971,7 +973,7 @@ static void fork_hash_lock(struct hash_lock *old_lock, struct data_vio *new_agen * path. * @lock: The hash lock. * @data_vio: The data_vio to deduplicate using the hash lock. - * @has_claim: true if the data_vio already has claimed an increment from the duplicate lock. + * @has_claim: True if the data_vio already has claimed an increment from the duplicate lock. * * If no increments are available, this will roll over to a new hash lock and launch the data_vio * as the writing agent for that lock. @@ -996,7 +998,7 @@ static void launch_dedupe(struct hash_lock *lock, struct data_vio *data_vio, * true copy of their data on disk. * @lock: The hash lock. * @agent: The data_vio acting as the agent for the lock. - * @agent_is_done: true only if the agent has already written or deduplicated against its data. + * @agent_is_done: True only if the agent has already written or deduplicated against its data. * * If the agent itself needs to deduplicate, an increment for it must already have been claimed * from the duplicate lock, ensuring the hash lock will still have a data_vio holding it. @@ -2146,8 +2148,8 @@ static void start_expiration_timer(struct dedupe_context *context) /** * report_dedupe_timeouts() - Record and eventually report that some dedupe requests reached their * expiration time without getting answers, so we timed them out. - * @zones: the hash zones. - * @timeouts: the number of newly timed out requests. + * @zones: The hash zones. + * @timeouts: The number of newly timed out requests. */ static void report_dedupe_timeouts(struct hash_zones *zones, unsigned int timeouts) { @@ -2509,6 +2511,8 @@ static void initiate_suspend_index(struct admin_state *state) /** * suspend_index() - Suspend the UDS index prior to draining hash zones. + * @context: Not used. + * @completion: The completion for the suspend operation. * * Implements vdo_action_preamble_fn */ @@ -2521,21 +2525,13 @@ static void suspend_index(void *context, struct vdo_completion *completion) initiate_suspend_index); } -/** - * initiate_drain() - Initiate a drain. - * - * Implements vdo_admin_initiator_fn. - */ +/** Implements vdo_admin_initiator_fn. */ static void initiate_drain(struct admin_state *state) { check_for_drain_complete(container_of(state, struct hash_zone, state)); } -/** - * drain_hash_zone() - Drain a hash zone. - * - * Implements vdo_zone_action_fn. - */ +/** Implements vdo_zone_action_fn. */ static void drain_hash_zone(void *context, zone_count_t zone_number, struct vdo_completion *parent) { @@ -2572,6 +2568,8 @@ static void launch_dedupe_state_change(struct hash_zones *zones) /** * resume_index() - Resume the UDS index prior to resuming hash zones. + * @context: Not used. + * @parent: The completion for the resume operation. * * Implements vdo_action_preamble_fn */ @@ -2602,11 +2600,7 @@ static void resume_index(void *context, struct vdo_completion *parent) vdo_finish_completion(parent); } -/** - * resume_hash_zone() - Resume a hash zone. - * - * Implements vdo_zone_action_fn. - */ +/** Implements vdo_zone_action_fn. */ static void resume_hash_zone(void *context, zone_count_t zone_number, struct vdo_completion *parent) { @@ -2634,7 +2628,7 @@ void vdo_resume_hash_zones(struct hash_zones *zones, struct vdo_completion *pare /** * get_hash_zone_statistics() - Add the statistics for this hash zone to the tally for all zones. * @zone: The hash zone to query. - * @tally: The tally + * @tally: The tally. */ static void get_hash_zone_statistics(const struct hash_zone *zone, struct hash_lock_statistics *tally) @@ -2680,8 +2674,8 @@ static void get_index_statistics(struct hash_zones *zones, /** * vdo_get_dedupe_statistics() - Tally the statistics from all the hash zones and the UDS index. - * @zones: The hash zones to query - * @stats: A structure to store the statistics + * @zones: The hash zones to query. + * @stats: A structure to store the statistics. * * Return: The sum of the hash lock statistics from all hash zones plus the statistics from the UDS * index @@ -2856,9 +2850,9 @@ void vdo_set_dedupe_index_min_timer_interval(unsigned int value) /** * acquire_context() - Acquire a dedupe context from a hash_zone if any are available. - * @zone: the hash zone + * @zone: The hash zone. * - * Return: A dedupe_context or NULL if none are available + * Return: A dedupe_context or NULL if none are available. */ static struct dedupe_context * __must_check acquire_context(struct hash_zone *zone) { diff --git a/drivers/md/dm-vdo/dm-vdo-target.c b/drivers/md/dm-vdo/dm-vdo-target.c index 0e04c2021682..6af40d40f255 100644 --- a/drivers/md/dm-vdo/dm-vdo-target.c +++ b/drivers/md/dm-vdo/dm-vdo-target.c @@ -1144,6 +1144,7 @@ static bool vdo_uses_device(struct vdo *vdo, const void *context) /** * get_thread_id_for_phase() - Get the thread id for the current phase of the admin operation in * progress. + * @vdo: The vdo. */ static thread_id_t __must_check get_thread_id_for_phase(struct vdo *vdo) { @@ -1188,9 +1189,9 @@ static struct vdo_completion *prepare_admin_completion(struct vdo *vdo, /** * advance_phase() - Increment the phase of the current admin operation and prepare the admin * completion to run on the thread for the next phase. - * @vdo: The on which an admin operation is being performed + * @vdo: The vdo on which an admin operation is being performed. * - * Return: The current phase + * Return: The current phase. */ static u32 advance_phase(struct vdo *vdo) { diff --git a/drivers/md/dm-vdo/encodings.c b/drivers/md/dm-vdo/encodings.c index b7cc0f41caca..dd59691be840 100644 --- a/drivers/md/dm-vdo/encodings.c +++ b/drivers/md/dm-vdo/encodings.c @@ -432,7 +432,10 @@ static void encode_block_map_state_2_0(u8 *buffer, size_t *offset, /** * vdo_compute_new_forest_pages() - Compute the number of pages which must be allocated at each * level in order to grow the forest to a new number of entries. + * @root_count: The number of block map roots. + * @old_sizes: The sizes of the old tree segments. * @entries: The new number of entries the block map must address. + * @new_sizes: The sizes of the new tree segments. * * Return: The total number of non-leaf pages required. */ @@ -462,6 +465,9 @@ block_count_t vdo_compute_new_forest_pages(root_count_t root_count, /** * encode_recovery_journal_state_7_0() - Encode the state of a recovery journal. + * @buffer: A buffer to store the encoding. + * @offset: The offset in the buffer at which to encode. + * @state: The recovery journal state to encode. * * Return: VDO_SUCCESS or an error code. */ @@ -484,6 +490,7 @@ static void encode_recovery_journal_state_7_0(u8 *buffer, size_t *offset, /** * decode_recovery_journal_state_7_0() - Decode the state of a recovery journal saved in a buffer. * @buffer: The buffer containing the saved state. + * @offset: The offset to start decoding from. * @state: A pointer to a recovery journal state to hold the result of a successful decode. * * Return: VDO_SUCCESS or an error code. @@ -544,6 +551,9 @@ const char *vdo_get_journal_operation_name(enum journal_operation operation) /** * encode_slab_depot_state_2_0() - Encode the state of a slab depot into a buffer. + * @buffer: A buffer to store the encoding. + * @offset: The offset in the buffer at which to encode. + * @state: The slab depot state to encode. */ static void encode_slab_depot_state_2_0(u8 *buffer, size_t *offset, struct slab_depot_state_2_0 state) @@ -570,6 +580,9 @@ static void encode_slab_depot_state_2_0(u8 *buffer, size_t *offset, /** * decode_slab_depot_state_2_0() - Decode slab depot component state version 2.0 from a buffer. + * @buffer: The buffer being decoded. + * @offset: The offset to start decoding from. + * @state: A pointer to a slab depot state to hold the decoded result. * * Return: VDO_SUCCESS or an error code. */ @@ -1156,6 +1169,9 @@ static struct vdo_component unpack_vdo_component_41_0(struct packed_vdo_componen /** * decode_vdo_component() - Decode the component data for the vdo itself out of the super block. + * @buffer: The buffer being decoded. + * @offset: The offset to start decoding from. + * @component: The vdo component structure to decode into. * * Return: VDO_SUCCESS or an error. */ @@ -1290,7 +1306,7 @@ void vdo_destroy_component_states(struct vdo_component_states *states) * understand. * @buffer: The buffer being decoded. * @offset: The offset to start decoding from. - * @geometry: The vdo geometry + * @geometry: The vdo geometry. * @states: An object to hold the successfully decoded state. * * Return: VDO_SUCCESS or an error. @@ -1329,7 +1345,7 @@ static int __must_check decode_components(u8 *buffer, size_t *offset, /** * vdo_decode_component_states() - Decode the payload of a super block. * @buffer: The buffer containing the encoded super block contents. - * @geometry: The vdo geometry + * @geometry: The vdo geometry. * @states: A pointer to hold the decoded states. * * Return: VDO_SUCCESS or an error. @@ -1383,6 +1399,9 @@ int vdo_validate_component_states(struct vdo_component_states *states, /** * vdo_encode_component_states() - Encode the state of all vdo components in the super block. + * @buffer: A buffer to store the encoding. + * @offset: The offset into the buffer to start the encoding. + * @states: The component states to encode. */ static void vdo_encode_component_states(u8 *buffer, size_t *offset, const struct vdo_component_states *states) @@ -1402,6 +1421,8 @@ static void vdo_encode_component_states(u8 *buffer, size_t *offset, /** * vdo_encode_super_block() - Encode a super block into its on-disk representation. + * @buffer: A buffer to store the encoding. + * @states: The component states to encode. */ void vdo_encode_super_block(u8 *buffer, struct vdo_component_states *states) { @@ -1426,6 +1447,7 @@ void vdo_encode_super_block(u8 *buffer, struct vdo_component_states *states) /** * vdo_decode_super_block() - Decode a super block from its on-disk representation. + * @buffer: The buffer to decode from. */ int vdo_decode_super_block(u8 *buffer) { diff --git a/drivers/md/dm-vdo/flush.c b/drivers/md/dm-vdo/flush.c index dd4fdee2ca0c..82a259ef1601 100644 --- a/drivers/md/dm-vdo/flush.c +++ b/drivers/md/dm-vdo/flush.c @@ -522,11 +522,7 @@ static void vdo_complete_flush(struct vdo_flush *flush) vdo_enqueue_completion(completion, BIO_Q_FLUSH_PRIORITY); } -/** - * initiate_drain() - Initiate a drain. - * - * Implements vdo_admin_initiator_fn. - */ +/** Implements vdo_admin_initiator_fn. */ static void initiate_drain(struct admin_state *state) { check_for_drain_complete(container_of(state, struct flusher, state)); diff --git a/drivers/md/dm-vdo/funnel-workqueue.c b/drivers/md/dm-vdo/funnel-workqueue.c index 0613c82bbe8e..8a79b33b8b09 100644 --- a/drivers/md/dm-vdo/funnel-workqueue.c +++ b/drivers/md/dm-vdo/funnel-workqueue.c @@ -372,6 +372,13 @@ static int make_simple_work_queue(const char *thread_name_prefix, const char *na /** * vdo_make_work_queue() - Create a work queue; if multiple threads are requested, completions will * be distributed to them in round-robin fashion. + * @thread_name_prefix: A prefix for the thread names to identify them as a vdo thread. + * @name: A base name to identify this queue. + * @owner: The vdo_thread structure to manage this queue. + * @type: The type of queue to create. + * @thread_count: The number of actual threads handling this queue. + * @thread_privates: An array of private contexts, one for each thread; may be NULL. + * @queue_ptr: A pointer to return the new work queue. * * Each queue is associated with a struct vdo_thread which has a single vdo thread id. Regardless * of the actual number of queues and threads allocated here, code outside of the queue diff --git a/drivers/md/dm-vdo/io-submitter.c b/drivers/md/dm-vdo/io-submitter.c index 11d47770b54d..e26d75f8366d 100644 --- a/drivers/md/dm-vdo/io-submitter.c +++ b/drivers/md/dm-vdo/io-submitter.c @@ -118,6 +118,7 @@ static void send_bio_to_device(struct vio *vio, struct bio *bio) /** * vdo_submit_vio() - Submits a vio's bio to the underlying block device. May block if the device * is busy. This callback should be used by vios which did not attempt to merge. + * @completion: The vio to submit. */ void vdo_submit_vio(struct vdo_completion *completion) { @@ -133,7 +134,7 @@ void vdo_submit_vio(struct vdo_completion *completion) * The list will always contain at least one entry (the bio for the vio on which it is called), but * other bios may have been merged with it as well. * - * Return: bio The head of the bio list to submit. + * Return: The head of the bio list to submit. */ static struct bio *get_bio_list(struct vio *vio) { @@ -158,6 +159,7 @@ static struct bio *get_bio_list(struct vio *vio) /** * submit_data_vio() - Submit a data_vio's bio to the storage below along with * any bios that have been merged with it. + * @completion: The vio to submit. * * Context: This call may block and so should only be called from a bio thread. */ @@ -184,7 +186,7 @@ static void submit_data_vio(struct vdo_completion *completion) * There are two types of merging possible, forward and backward, which are distinguished by a flag * that uses kernel elevator terminology. * - * Return: the vio to merge to, NULL if no merging is possible. + * Return: The vio to merge to, NULL if no merging is possible. */ static struct vio *get_mergeable_locked(struct int_map *map, struct vio *vio, bool back_merge) @@ -262,7 +264,7 @@ static int merge_to_next_head(struct int_map *bio_map, struct vio *vio, * * Currently this is only used for data_vios, but is broken out for future use with metadata vios. * - * Return: whether or not the vio was merged. + * Return: Whether or not the vio was merged. */ static bool try_bio_map_merge(struct vio *vio) { @@ -306,7 +308,7 @@ static bool try_bio_map_merge(struct vio *vio) /** * vdo_submit_data_vio() - Submit I/O for a data_vio. - * @data_vio: the data_vio for which to issue I/O. + * @data_vio: The data_vio for which to issue I/O. * * If possible, this I/O will be merged other pending I/Os. Otherwise, the data_vio will be sent to * the appropriate bio zone directly. @@ -321,13 +323,13 @@ void vdo_submit_data_vio(struct data_vio *data_vio) /** * __submit_metadata_vio() - Submit I/O for a metadata vio. - * @vio: the vio for which to issue I/O - * @physical: the physical block number to read or write - * @callback: the bio endio function which will be called after the I/O completes - * @error_handler: the handler for submission or I/O errors (may be NULL) - * @operation: the type of I/O to perform - * @data: the buffer to read or write (may be NULL) - * @size: the I/O amount in bytes + * @vio: The vio for which to issue I/O. + * @physical: The physical block number to read or write. + * @callback: The bio endio function which will be called after the I/O completes. + * @error_handler: The handler for submission or I/O errors; may be NULL. + * @operation: The type of I/O to perform. + * @data: The buffer to read or write; may be NULL. + * @size: The I/O amount in bytes. * * The vio is enqueued on a vdo bio queue so that bio submission (which may block) does not block * other vdo threads. @@ -441,7 +443,7 @@ int vdo_make_io_submitter(unsigned int thread_count, unsigned int rotation_inter /** * vdo_cleanup_io_submitter() - Tear down the io_submitter fields as needed for a physical layer. - * @io_submitter: The I/O submitter data to tear down (may be NULL). + * @io_submitter: The I/O submitter data to tear down; may be NULL. */ void vdo_cleanup_io_submitter(struct io_submitter *io_submitter) { diff --git a/drivers/md/dm-vdo/logical-zone.c b/drivers/md/dm-vdo/logical-zone.c index 026f031ffc9e..0a27e60a9dfd 100644 --- a/drivers/md/dm-vdo/logical-zone.c +++ b/drivers/md/dm-vdo/logical-zone.c @@ -159,21 +159,13 @@ static void check_for_drain_complete(struct logical_zone *zone) vdo_finish_draining(&zone->state); } -/** - * initiate_drain() - Initiate a drain. - * - * Implements vdo_admin_initiator_fn. - */ +/** Implements vdo_admin_initiator_fn. */ static void initiate_drain(struct admin_state *state) { check_for_drain_complete(container_of(state, struct logical_zone, state)); } -/** - * drain_logical_zone() - Drain a logical zone. - * - * Implements vdo_zone_action_fn. - */ +/** Implements vdo_zone_action_fn. */ static void drain_logical_zone(void *context, zone_count_t zone_number, struct vdo_completion *parent) { @@ -192,11 +184,7 @@ void vdo_drain_logical_zones(struct logical_zones *zones, parent); } -/** - * resume_logical_zone() - Resume a logical zone. - * - * Implements vdo_zone_action_fn. - */ +/** Implements vdo_zone_action_fn. */ static void resume_logical_zone(void *context, zone_count_t zone_number, struct vdo_completion *parent) { @@ -356,7 +344,7 @@ struct physical_zone *vdo_get_next_allocation_zone(struct logical_zone *zone) /** * vdo_dump_logical_zone() - Dump information about a logical zone to the log for debugging. - * @zone: The zone to dump + * @zone: The zone to dump. * * Context: the information is dumped in a thread-unsafe fashion. * diff --git a/drivers/md/dm-vdo/packer.c b/drivers/md/dm-vdo/packer.c index f70f5edabc10..666be6d557e1 100644 --- a/drivers/md/dm-vdo/packer.c +++ b/drivers/md/dm-vdo/packer.c @@ -35,10 +35,10 @@ static const struct version_number COMPRESSED_BLOCK_1_0 = { /** * vdo_get_compressed_block_fragment() - Get a reference to a compressed fragment from a compressed * block. - * @mapping_state [in] The mapping state for the look up. - * @compressed_block [in] The compressed block that was read from disk. - * @fragment_offset [out] The offset of the fragment within a compressed block. - * @fragment_size [out] The size of the fragment. + * @mapping_state: The mapping state describing the fragment. + * @block: The compressed block that was read from disk. + * @fragment_offset: The offset of the fragment within the compressed block. + * @fragment_size: The size of the fragment. * * Return: If a valid compressed fragment is found, VDO_SUCCESS; otherwise, VDO_INVALID_FRAGMENT if * the fragment is invalid. @@ -382,6 +382,7 @@ static void initialize_compressed_block(struct compressed_block *block, u16 size * @compression: The agent's compression_state to pack in to. * @data_vio: The data_vio to pack. * @offset: The offset into the compressed block at which to pack the fragment. + * @slot: The slot number in the compressed block. * @block: The compressed block which will be written out when batch is fully packed. * * Return: The new amount of space used. @@ -705,11 +706,7 @@ void vdo_increment_packer_flush_generation(struct packer *packer) vdo_flush_packer(packer); } -/** - * initiate_drain() - Initiate a drain. - * - * Implements vdo_admin_initiator_fn. - */ +/** Implements vdo_admin_initiator_fn. */ static void initiate_drain(struct admin_state *state) { struct packer *packer = container_of(state, struct packer, state); diff --git a/drivers/md/dm-vdo/physical-zone.c b/drivers/md/dm-vdo/physical-zone.c index a43b5c45fab7..686eb7d714e6 100644 --- a/drivers/md/dm-vdo/physical-zone.c +++ b/drivers/md/dm-vdo/physical-zone.c @@ -60,7 +60,7 @@ static inline bool has_lock_type(const struct pbn_lock *lock, enum pbn_lock_type * vdo_is_pbn_read_lock() - Check whether a pbn_lock is a read lock. * @lock: The lock to check. * - * Return: true if the lock is a read lock. + * Return: True if the lock is a read lock. */ bool vdo_is_pbn_read_lock(const struct pbn_lock *lock) { @@ -75,6 +75,7 @@ static inline void set_pbn_lock_type(struct pbn_lock *lock, enum pbn_lock_type t /** * vdo_downgrade_pbn_write_lock() - Downgrade a PBN write lock to a PBN read lock. * @lock: The PBN write lock to downgrade. + * @compressed_write: True if the written block was a compressed block. * * The lock holder count is cleared and the caller is responsible for setting the new count. */ @@ -582,7 +583,7 @@ static bool continue_allocating(struct data_vio *data_vio) * that fails try the next if possible. * @data_vio: The data_vio needing an allocation. * - * Return: true if a block was allocated, if not the data_vio will have been dispatched so the + * Return: True if a block was allocated, if not the data_vio will have been dispatched so the * caller must not touch it. */ bool vdo_allocate_block_in_zone(struct data_vio *data_vio) diff --git a/drivers/md/dm-vdo/recovery-journal.c b/drivers/md/dm-vdo/recovery-journal.c index de58184f538f..9cc0f0ff1664 100644 --- a/drivers/md/dm-vdo/recovery-journal.c +++ b/drivers/md/dm-vdo/recovery-journal.c @@ -109,7 +109,7 @@ static atomic_t *get_decrement_counter(struct recovery_journal *journal, * @journal: The recovery journal. * @lock_number: The lock to check. * - * Return: true if the journal zone is locked. + * Return: True if the journal zone is locked. */ static bool is_journal_zone_locked(struct recovery_journal *journal, block_count_t lock_number) @@ -217,7 +217,7 @@ static struct recovery_journal_block * __must_check pop_free_list(struct recover * Indicates it has any uncommitted entries, which includes both entries not written and entries * written but not yet acknowledged. * - * Return: true if the block has any uncommitted entries. + * Return: True if the block has any uncommitted entries. */ static inline bool __must_check is_block_dirty(const struct recovery_journal_block *block) { @@ -228,7 +228,7 @@ static inline bool __must_check is_block_dirty(const struct recovery_journal_blo * is_block_empty() - Check whether a journal block is empty. * @block: The block to check. * - * Return: true if the block has no entries. + * Return: True if the block has no entries. */ static inline bool __must_check is_block_empty(const struct recovery_journal_block *block) { @@ -239,7 +239,7 @@ static inline bool __must_check is_block_empty(const struct recovery_journal_blo * is_block_full() - Check whether a journal block is full. * @block: The block to check. * - * Return: true if the block is full. + * Return: True if the block is full. */ static inline bool __must_check is_block_full(const struct recovery_journal_block *block) { @@ -260,6 +260,8 @@ static void assert_on_journal_thread(struct recovery_journal *journal, /** * continue_waiter() - Release a data_vio from the journal. + * @waiter: The data_vio waiting on journal activity. + * @context: The result of the journal operation. * * Invoked whenever a data_vio is to be released from the journal, either because its entry was * committed to disk, or because there was an error. Implements waiter_callback_fn. @@ -273,7 +275,7 @@ static void continue_waiter(struct vdo_waiter *waiter, void *context) * has_block_waiters() - Check whether the journal has any waiters on any blocks. * @journal: The journal in question. * - * Return: true if any block has a waiter. + * Return: True if any block has a waiter. */ static inline bool has_block_waiters(struct recovery_journal *journal) { @@ -296,7 +298,7 @@ static void notify_commit_waiters(struct recovery_journal *journal); * suspend_lock_counter() - Prevent the lock counter from notifying. * @counter: The counter. * - * Return: true if the lock counter was not notifying and hence the suspend was efficacious. + * Return: True if the lock counter was not notifying and hence the suspend was efficacious. */ static bool suspend_lock_counter(struct lock_counter *counter) { @@ -416,7 +418,7 @@ sequence_number_t vdo_get_recovery_journal_current_sequence_number(struct recove * * The head is the lowest sequence number of the block map head and the slab journal head. * - * Return: the head of the journal. + * Return: The head of the journal. */ static inline sequence_number_t get_recovery_journal_head(const struct recovery_journal *journal) { @@ -535,7 +537,7 @@ static void initialize_journal_state(struct recovery_journal *journal) * vdo_get_recovery_journal_length() - Get the number of usable recovery journal blocks. * @journal_size: The size of the recovery journal in blocks. * - * Return: the number of recovery journal blocks usable for entries. + * Return: The number of recovery journal blocks usable for entries. */ block_count_t vdo_get_recovery_journal_length(block_count_t journal_size) { @@ -1078,6 +1080,8 @@ static void update_usages(struct recovery_journal *journal, struct data_vio *dat /** * assign_entry() - Assign an entry waiter to the active block. + * @waiter: The data_vio. + * @context: The recovery journal block. * * Implements waiter_callback_fn. */ @@ -1165,6 +1169,8 @@ static void recycle_journal_block(struct recovery_journal_block *block) /** * continue_committed_waiter() - invoked whenever a VIO is to be released from the journal because * its entry was committed to disk. + * @waiter: The data_vio waiting on a journal write. + * @context: A pointer to the recovery journal. * * Implements waiter_callback_fn. */ @@ -1362,6 +1368,8 @@ static void add_queued_recovery_entries(struct recovery_journal_block *block) /** * write_block() - Issue a block for writing. + * @waiter: The recovery journal block to write. + * @context: Not used. * * Implements waiter_callback_fn. */ @@ -1611,11 +1619,7 @@ void vdo_release_journal_entry_lock(struct recovery_journal *journal, smp_mb__after_atomic(); } -/** - * initiate_drain() - Initiate a drain. - * - * Implements vdo_admin_initiator_fn. - */ +/** Implements vdo_admin_initiator_fn. */ static void initiate_drain(struct admin_state *state) { check_for_drain_complete(container_of(state, struct recovery_journal, state)); diff --git a/drivers/md/dm-vdo/slab-depot.c b/drivers/md/dm-vdo/slab-depot.c index f3d80ff7bef5..034ecaa51f48 100644 --- a/drivers/md/dm-vdo/slab-depot.c +++ b/drivers/md/dm-vdo/slab-depot.c @@ -40,7 +40,7 @@ static const bool NORMAL_OPERATION = true; /** * get_lock() - Get the lock object for a slab journal block by sequence number. - * @journal: vdo_slab journal to retrieve from. + * @journal: The vdo_slab journal to retrieve from. * @sequence_number: Sequence number of the block. * * Return: The lock object for the given sequence number. @@ -110,7 +110,7 @@ static void initialize_journal_state(struct slab_journal *journal) * block_is_full() - Check whether a journal block is full. * @journal: The slab journal for the block. * - * Return: true if the tail block is full. + * Return: True if the tail block is full. */ static bool __must_check block_is_full(struct slab_journal *journal) { @@ -127,10 +127,11 @@ static void release_journal_locks(struct vdo_waiter *waiter, void *context); /** * is_slab_journal_blank() - Check whether a slab's journal is blank. + * @slab: The slab to check. * * A slab journal is blank if it has never had any entries recorded in it. * - * Return: true if the slab's journal has never been modified. + * Return: True if the slab's journal has never been modified. */ static bool is_slab_journal_blank(const struct vdo_slab *slab) { @@ -227,6 +228,7 @@ static u8 __must_check compute_fullness_hint(struct slab_depot *depot, /** * check_summary_drain_complete() - Check whether an allocators summary has finished draining. + * @allocator: The allocator to check. */ static void check_summary_drain_complete(struct block_allocator *allocator) { @@ -349,7 +351,7 @@ static void launch_write(struct slab_summary_block *block) /** * update_slab_summary_entry() - Update the entry for a slab. - * @slab: The slab whose entry is to be updated + * @slab: The slab whose entry is to be updated. * @waiter: The waiter that is updating the summary. * @tail_block_offset: The offset of the slab journal's tail block. * @load_ref_counts: Whether the reference counts must be loaded from disk on the vdo load. @@ -654,6 +656,7 @@ static void update_tail_block_location(struct slab_journal *journal) /** * reopen_slab_journal() - Reopen a slab's journal by emptying it and then adding pending entries. + * @slab: The slab to reopen. */ static void reopen_slab_journal(struct vdo_slab *slab) { @@ -839,8 +842,6 @@ static void commit_tail(struct slab_journal *journal) * @sbn: The slab block number of the entry to encode. * @operation: The type of the entry. * @increment: True if this is an increment. - * - * Exposed for unit tests. */ static void encode_slab_journal_entry(struct slab_journal_block_header *tail_header, slab_journal_payload *payload, @@ -951,7 +952,7 @@ static inline block_count_t journal_length(const struct slab_journal *journal) * @parent: The completion to notify when there is space to add the entry if the entry could not be * added immediately. * - * Return: true if the entry was added immediately. + * Return: True if the entry was added immediately. */ bool vdo_attempt_replay_into_slab(struct vdo_slab *slab, physical_block_number_t pbn, enum journal_operation operation, bool increment, @@ -1003,7 +1004,7 @@ bool vdo_attempt_replay_into_slab(struct vdo_slab *slab, physical_block_number_t * requires_reaping() - Check whether the journal must be reaped before adding new entries. * @journal: The journal to check. * - * Return: true if the journal must be reaped. + * Return: True if the journal must be reaped. */ static bool requires_reaping(const struct slab_journal *journal) { @@ -1275,6 +1276,8 @@ static void dirty_block(struct reference_block *block) /** * get_reference_block() - Get the reference block that covers the given block index. + * @slab: The slab containing the references. + * @index: The index of the physical block. */ static struct reference_block * __must_check get_reference_block(struct vdo_slab *slab, slab_block_number index) @@ -1379,7 +1382,8 @@ static void prioritize_slab(struct vdo_slab *slab) /** * adjust_free_block_count() - Adjust the free block count and (if needed) reprioritize the slab. - * @incremented: true if the free block count went up. + * @slab: The slab. + * @incremented: True if the free block count went up. */ static void adjust_free_block_count(struct vdo_slab *slab, bool incremented) { @@ -1885,6 +1889,7 @@ static void add_entries(struct slab_journal *journal) /** * reset_search_cursor() - Reset the free block search back to the first reference counter in the * first reference block of a slab. + * @slab: The slab. */ static void reset_search_cursor(struct vdo_slab *slab) { @@ -1892,17 +1897,17 @@ static void reset_search_cursor(struct vdo_slab *slab) cursor->block = cursor->first_block; cursor->index = 0; - /* Unit tests have slabs with only one reference block (and it's a runt). */ cursor->end_index = min_t(u32, COUNTS_PER_BLOCK, slab->block_count); } /** * advance_search_cursor() - Advance the search cursor to the start of the next reference block in - * a slab, + * a slab. + * @slab: The slab. * * Wraps around to the first reference block if the current block is the last reference block. * - * Return: true unless the cursor was at the last reference block. + * Return: True unless the cursor was at the last reference block. */ static bool advance_search_cursor(struct vdo_slab *slab) { @@ -1933,6 +1938,9 @@ static bool advance_search_cursor(struct vdo_slab *slab) /** * vdo_adjust_reference_count_for_rebuild() - Adjust the reference count of a block during rebuild. + * @depot: The slab depot. + * @pbn: The physical block number to adjust. + * @operation: The type opf operation. * * Return: VDO_SUCCESS or an error. */ @@ -2038,9 +2046,7 @@ static inline slab_block_number find_zero_byte_in_word(const u8 *word_ptr, * @slab: The slab counters to scan. * @index_ptr: A pointer to hold the array index of the free block. * - * Exposed for unit testing. - * - * Return: true if a free block was found in the specified range. + * Return: True if a free block was found in the specified range. */ static bool find_free_block(const struct vdo_slab *slab, slab_block_number *index_ptr) { @@ -2097,7 +2103,7 @@ static bool find_free_block(const struct vdo_slab *slab, slab_block_number *inde * @slab: The slab to search. * @free_index_ptr: A pointer to receive the array index of the zero reference count. * - * Return: true if an unreferenced counter was found. + * Return: True if an unreferenced counter was found. */ static bool search_current_reference_block(const struct vdo_slab *slab, slab_block_number *free_index_ptr) @@ -2116,7 +2122,7 @@ static bool search_current_reference_block(const struct vdo_slab *slab, * counter index saved in the search cursor and searching up to the end of the last reference * block. The search does not wrap. * - * Return: true if an unreferenced counter was found. + * Return: True if an unreferenced counter was found. */ static bool search_reference_blocks(struct vdo_slab *slab, slab_block_number *free_index_ptr) @@ -2136,6 +2142,8 @@ static bool search_reference_blocks(struct vdo_slab *slab, /** * make_provisional_reference() - Do the bookkeeping for making a provisional reference. + * @slab: The slab. + * @block_number: The index for the physical block to reference. */ static void make_provisional_reference(struct vdo_slab *slab, slab_block_number block_number) @@ -2155,6 +2163,7 @@ static void make_provisional_reference(struct vdo_slab *slab, /** * dirty_all_reference_blocks() - Mark all reference count blocks in a slab as dirty. + * @slab: The slab. */ static void dirty_all_reference_blocks(struct vdo_slab *slab) { @@ -2173,10 +2182,10 @@ static inline bool journal_points_equal(struct journal_point first, /** * match_bytes() - Check an 8-byte word for bytes matching the value specified - * @input: A word to examine the bytes of - * @match: The byte value sought + * @input: A word to examine the bytes of. + * @match: The byte value sought. * - * Return: 1 in each byte when the corresponding input byte matched, 0 otherwise + * Return: 1 in each byte when the corresponding input byte matched, 0 otherwise. */ static inline u64 match_bytes(u64 input, u8 match) { @@ -2191,12 +2200,12 @@ static inline u64 match_bytes(u64 input, u8 match) /** * count_valid_references() - Process a newly loaded refcount array - * @counters: the array of counters from a metadata block + * @counters: The array of counters from a metadata block. * - * Scan a 8-byte-aligned array of counters, fixing up any "provisional" values that weren't - * cleaned up at shutdown, changing them internally to "empty". + * Scan an 8-byte-aligned array of counters, fixing up any provisional values that + * weren't cleaned up at shutdown, changing them internally to zero. * - * Return: the number of blocks that are referenced (counters not "empty") + * Return: The number of blocks with a non-zero reference count. */ static unsigned int count_valid_references(vdo_refcount_t *counters) { @@ -2351,6 +2360,7 @@ static void load_reference_block_group(struct vdo_waiter *waiter, void *context) /** * load_reference_blocks() - Load a slab's reference blocks from the underlying storage into a * pre-allocated reference counter. + * @slab: The slab. */ static void load_reference_blocks(struct vdo_slab *slab) { @@ -2375,6 +2385,7 @@ static void load_reference_blocks(struct vdo_slab *slab) /** * drain_slab() - Drain all reference count I/O. + * @slab: The slab. * * Depending upon the type of drain being performed (as recorded in the ref_count's vdo_slab), the * reference blocks may be loaded from disk or dirty reference blocks may be written out. @@ -2564,6 +2575,7 @@ static void read_slab_journal_tail(struct vdo_waiter *waiter, void *context) /** * load_slab_journal() - Load a slab's journal by reading the journal's tail. + * @slab: The slab. */ static void load_slab_journal(struct vdo_slab *slab) { @@ -2663,11 +2675,7 @@ static void queue_slab(struct vdo_slab *slab) prioritize_slab(slab); } -/** - * initiate_slab_action() - Initiate a slab action. - * - * Implements vdo_admin_initiator_fn. - */ +/** Implements vdo_admin_initiator_fn. */ static void initiate_slab_action(struct admin_state *state) { struct vdo_slab *slab = container_of(state, struct vdo_slab, state); @@ -2720,7 +2728,7 @@ static struct vdo_slab *get_next_slab(struct slab_scrubber *scrubber) * has_slabs_to_scrub() - Check whether a scrubber has slabs to scrub. * @scrubber: The scrubber to check. * - * Return: true if the scrubber has slabs to scrub. + * Return: True if the scrubber has slabs to scrub. */ static inline bool __must_check has_slabs_to_scrub(struct slab_scrubber *scrubber) { @@ -2741,6 +2749,7 @@ static void uninitialize_scrubber_vio(struct slab_scrubber *scrubber) * finish_scrubbing() - Stop scrubbing, either because there are no more slabs to scrub or because * there's been an error. * @scrubber: The scrubber. + * @result: The result of the scrubbing operation. */ static void finish_scrubbing(struct slab_scrubber *scrubber, int result) { @@ -3132,11 +3141,13 @@ static struct vdo_slab *next_slab(struct slab_iterator *iterator) /** * abort_waiter() - Abort vios waiting to make journal entries when read-only. + * @waiter: A waiting data_vio. + * @context: Not used. * * This callback is invoked on all vios waiting to make slab journal entries after the VDO has gone * into read-only mode. Implements waiter_callback_fn. */ -static void abort_waiter(struct vdo_waiter *waiter, void *context __always_unused) +static void abort_waiter(struct vdo_waiter *waiter, void __always_unused *context) { struct reference_updater *updater = container_of(waiter, struct reference_updater, waiter); @@ -3536,7 +3547,7 @@ static void initiate_load(struct admin_state *state) /** * vdo_notify_slab_journals_are_recovered() - Inform a block allocator that its slab journals have * been recovered from the recovery journal. - * @completion The allocator completion + * @completion: The allocator completion. */ void vdo_notify_slab_journals_are_recovered(struct vdo_completion *completion) { @@ -3775,7 +3786,7 @@ static int initialize_slab_journal(struct vdo_slab *slab) * in the slab. * @allocator: The block allocator to which the slab belongs. * @slab_number: The slab number of the slab. - * @is_new: true if this slab is being allocated as part of a resize. + * @is_new: True if this slab is being allocated as part of a resize. * @slab_ptr: A pointer to receive the new slab. * * Return: VDO_SUCCESS or an error code. @@ -3894,11 +3905,7 @@ void vdo_abandon_new_slabs(struct slab_depot *depot) vdo_free(vdo_forget(depot->new_slabs)); } -/** - * get_allocator_thread_id() - Get the ID of the thread on which a given allocator operates. - * - * Implements vdo_zone_thread_getter_fn. - */ +/** Implements vdo_zone_thread_getter_fn. */ static thread_id_t get_allocator_thread_id(void *context, zone_count_t zone_number) { return ((struct slab_depot *) context)->allocators[zone_number].thread_id; @@ -3911,7 +3918,7 @@ static thread_id_t get_allocator_thread_id(void *context, zone_count_t zone_numb * @recovery_lock: The sequence number of the recovery journal block whose locks should be * released. * - * Return: true if the journal does hold a lock on the specified block (which it will release). + * Return: True if the journal released a lock on the specified block. */ static bool __must_check release_recovery_journal_lock(struct slab_journal *journal, sequence_number_t recovery_lock) @@ -3955,6 +3962,8 @@ static void release_tail_block_locks(void *context, zone_count_t zone_number, /** * prepare_for_tail_block_commit() - Prepare to commit oldest tail blocks. + * @context: The slab depot. + * @parent: The parent operation. * * Implements vdo_action_preamble_fn. */ @@ -3968,6 +3977,7 @@ static void prepare_for_tail_block_commit(void *context, struct vdo_completion * /** * schedule_tail_block_commit() - Schedule a tail block commit if necessary. + * @context: The slab depot. * * This method should not be called directly. Rather, call vdo_schedule_default_action() on the * depot's action manager. @@ -4361,6 +4371,7 @@ struct slab_depot_state_2_0 vdo_record_slab_depot(const struct slab_depot *depot /** * vdo_allocate_reference_counters() - Allocate the reference counters for all slabs in the depot. + * @depot: The slab depot. * * Context: This method may be called only before entering normal operation from the load thread. * @@ -4615,7 +4626,9 @@ static void load_summary_endio(struct bio *bio) } /** - * load_slab_summary() - The preamble of a load operation. + * load_slab_summary() - Load the slab summary before the slab data. + * @context: The slab depot. + * @parent: The load operation. * * Implements vdo_action_preamble_fn. */ @@ -4731,7 +4744,7 @@ void vdo_update_slab_depot_size(struct slab_depot *depot) * vdo_prepare_to_grow_slab_depot() - Allocate new memory needed for a resize of a slab depot to * the given size. * @depot: The depot to prepare to resize. - * @partition: The new depot partition + * @partition: The new depot partition. * * Return: VDO_SUCCESS or an error. */ @@ -4781,6 +4794,7 @@ int vdo_prepare_to_grow_slab_depot(struct slab_depot *depot, /** * finish_registration() - Finish registering new slabs now that all of the allocators have * received their new slabs. + * @context: The slab depot. * * Implements vdo_action_conclusion_fn. */ diff --git a/drivers/md/dm-vdo/vdo.c b/drivers/md/dm-vdo/vdo.c index 80b608674022..09fd0628d18c 100644 --- a/drivers/md/dm-vdo/vdo.c +++ b/drivers/md/dm-vdo/vdo.c @@ -181,6 +181,8 @@ static void assign_thread_ids(struct thread_config *config, /** * initialize_thread_config() - Initialize the thread mapping + * @counts: The number and types of threads to create. + * @config: The thread_config to initialize. * * If the logical, physical, and hash zone counts are all 0, a single thread will be shared by all * three plus the packer and recovery journal. Otherwise, there must be at least one of each type, @@ -884,6 +886,7 @@ const struct admin_state_code *vdo_get_admin_state(const struct vdo *vdo) /** * record_vdo() - Record the state of the VDO for encoding in the super block. + * @vdo: The vdo. */ static void record_vdo(struct vdo *vdo) { @@ -1277,7 +1280,7 @@ void vdo_enter_read_only_mode(struct vdo *vdo, int error_code) * vdo_is_read_only() - Check whether the VDO is read-only. * @vdo: The vdo. * - * Return: true if the vdo is read-only. + * Return: True if the vdo is read-only. * * This method may be called from any thread, as opposed to examining the VDO's state field which * is only safe to check from the admin thread. @@ -1291,7 +1294,7 @@ bool vdo_is_read_only(struct vdo *vdo) * vdo_in_read_only_mode() - Check whether a vdo is in read-only mode. * @vdo: The vdo to query. * - * Return: true if the vdo is in read-only mode. + * Return: True if the vdo is in read-only mode. */ bool vdo_in_read_only_mode(const struct vdo *vdo) { @@ -1302,7 +1305,7 @@ bool vdo_in_read_only_mode(const struct vdo *vdo) * vdo_in_recovery_mode() - Check whether the vdo is in recovery mode. * @vdo: The vdo to query. * - * Return: true if the vdo is in recovery mode. + * Return: True if the vdo is in recovery mode. */ bool vdo_in_recovery_mode(const struct vdo *vdo) { diff --git a/drivers/md/dm-vdo/vdo.h b/drivers/md/dm-vdo/vdo.h index 483ae873e002..1aaba73997b7 100644 --- a/drivers/md/dm-vdo/vdo.h +++ b/drivers/md/dm-vdo/vdo.h @@ -279,8 +279,10 @@ static inline bool vdo_uses_bio_ack_queue(struct vdo *vdo) /** * typedef vdo_filter_fn - Method type for vdo matching methods. + * @vdo: The vdo to match. + * @context: A parameter for the filter to use. * - * A filter function returns false if the vdo doesn't match. + * Return: True if the vdo matches the filter criteria, false if it doesn't. */ typedef bool (*vdo_filter_fn)(struct vdo *vdo, const void *context); diff --git a/drivers/md/dm-vdo/vio.c b/drivers/md/dm-vdo/vio.c index 8fc22fb14196..5ffc867d9c5e 100644 --- a/drivers/md/dm-vdo/vio.c +++ b/drivers/md/dm-vdo/vio.c @@ -398,8 +398,9 @@ void free_vio_pool(struct vio_pool *pool) /** * is_vio_pool_busy() - Check whether an vio pool has outstanding entries. + * @pool: The vio pool. * - * Return: true if the pool is busy. + * Return: True if the pool is busy. */ bool is_vio_pool_busy(struct vio_pool *pool) { diff --git a/drivers/md/dm-vdo/vio.h b/drivers/md/dm-vdo/vio.h index 4bfcb21901f1..7a8a6819aec4 100644 --- a/drivers/md/dm-vdo/vio.h +++ b/drivers/md/dm-vdo/vio.h @@ -156,8 +156,7 @@ static inline enum vdo_completion_priority get_metadata_priority(struct vio *vio /** * continue_vio() - Enqueue a vio to run its next callback. * @vio: The vio to continue. - * - * Return: The result of the current operation. + * @result: The result of the current operation. */ static inline void continue_vio(struct vio *vio, int result) { @@ -172,6 +171,9 @@ void vdo_count_completed_bios(struct bio *bio); /** * continue_vio_after_io() - Continue a vio now that its I/O has returned. + * @vio: The vio to continue. + * @callback: The next operation for this vio. + * @thread: Which thread to run the next operation on. */ static inline void continue_vio_after_io(struct vio *vio, vdo_action_fn callback, thread_id_t thread) diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c index 72047b47a7a0..c79de517afee 100644 --- a/drivers/md/dm-verity-fec.c +++ b/drivers/md/dm-verity-fec.c @@ -177,9 +177,11 @@ error: if (r < 0 && neras) DMERR_LIMIT("%s: FEC %llu: failed to correct: %d", v->data_dev->name, (unsigned long long)rsb, r); - else if (r > 0) + else if (r > 0) { DMWARN_LIMIT("%s: FEC %llu: corrected %d errors", v->data_dev->name, (unsigned long long)rsb, r); + atomic64_inc(&v->fec->corrected); + } return r; } @@ -188,14 +190,13 @@ error: * Locate data block erasures using verity hashes. */ static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io, - u8 *want_digest, u8 *data) + const u8 *want_digest, const u8 *data) { if (unlikely(verity_hash(v, io, data, 1 << v->data_dev_block_bits, - verity_io_real_digest(v, io)))) + io->tmp_digest))) return 0; - return memcmp(verity_io_real_digest(v, io), want_digest, - v->digest_size) != 0; + return memcmp(io->tmp_digest, want_digest, v->digest_size) != 0; } /* @@ -328,7 +329,7 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio) if (fio->bufs[n]) continue; - fio->bufs[n] = mempool_alloc(&v->fec->extra_pool, GFP_NOWAIT); + fio->bufs[n] = kmem_cache_alloc(v->fec->cache, GFP_NOWAIT); /* we can manage with even one buffer if necessary */ if (unlikely(!fio->bufs[n])) break; @@ -362,7 +363,7 @@ static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio) */ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io, struct dm_verity_fec_io *fio, u64 rsb, u64 offset, - bool use_erasures) + const u8 *want_digest, bool use_erasures) { int r, neras = 0; unsigned int pos; @@ -388,12 +389,11 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io, /* Always re-validate the corrected block against the expected hash */ r = verity_hash(v, io, fio->output, 1 << v->data_dev_block_bits, - verity_io_real_digest(v, io)); + io->tmp_digest); if (unlikely(r < 0)) return r; - if (memcmp(verity_io_real_digest(v, io), verity_io_want_digest(v, io), - v->digest_size)) { + if (memcmp(io->tmp_digest, want_digest, v->digest_size)) { DMERR_LIMIT("%s: FEC %llu: failed to correct (%d erasures)", v->data_dev->name, (unsigned long long)rsb, neras); return -EILSEQ; @@ -404,7 +404,8 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io, /* Correct errors in a block. Copies corrected block to dest. */ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, - enum verity_block_type type, sector_t block, u8 *dest) + enum verity_block_type type, const u8 *want_digest, + sector_t block, u8 *dest) { int r; struct dm_verity_fec_io *fio = fec_io(io); @@ -413,10 +414,8 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, if (!verity_fec_is_enabled(v)) return -EOPNOTSUPP; - if (fio->level >= DM_VERITY_FEC_MAX_RECURSION) { - DMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name); + if (fio->level) return -EIO; - } fio->level++; @@ -447,9 +446,9 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, * them first. Do a second attempt with erasures if the corruption is * bad enough. */ - r = fec_decode_rsb(v, io, fio, rsb, offset, false); + r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, false); if (r < 0) { - r = fec_decode_rsb(v, io, fio, rsb, offset, true); + r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, true); if (r < 0) goto done; } @@ -479,7 +478,8 @@ void verity_fec_finish_io(struct dm_verity_io *io) mempool_free(fio->bufs[n], &f->prealloc_pool); fec_for_each_extra_buffer(fio, n) - mempool_free(fio->bufs[n], &f->extra_pool); + if (fio->bufs[n]) + kmem_cache_free(f->cache, fio->bufs[n]); mempool_free(fio->output, &f->output_pool); } @@ -531,7 +531,6 @@ void verity_fec_dtr(struct dm_verity *v) mempool_exit(&f->rs_pool); mempool_exit(&f->prealloc_pool); - mempool_exit(&f->extra_pool); mempool_exit(&f->output_pool); kmem_cache_destroy(f->cache); @@ -784,12 +783,6 @@ int verity_fec_ctr(struct dm_verity *v) return ret; } - ret = mempool_init_slab_pool(&f->extra_pool, 0, f->cache); - if (ret) { - ti->error = "Cannot allocate FEC buffer extra pool"; - return ret; - } - /* Preallocate an output buffer for each thread */ ret = mempool_init_kmalloc_pool(&f->output_pool, num_online_cpus(), 1 << v->data_dev_block_bits); diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h index 09123a612953..5fd267873812 100644 --- a/drivers/md/dm-verity-fec.h +++ b/drivers/md/dm-verity-fec.h @@ -23,9 +23,6 @@ #define DM_VERITY_FEC_BUF_MAX \ (1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS)) -/* maximum recursion level for verity_fec_decode */ -#define DM_VERITY_FEC_MAX_RECURSION 4 - #define DM_VERITY_OPT_FEC_DEV "use_fec_from_device" #define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks" #define DM_VERITY_OPT_FEC_START "fec_start" @@ -45,9 +42,9 @@ struct dm_verity_fec { unsigned char rsn; /* N of RS(M, N) */ mempool_t rs_pool; /* mempool for fio->rs */ mempool_t prealloc_pool; /* mempool for preallocated buffers */ - mempool_t extra_pool; /* mempool for extra buffers */ mempool_t output_pool; /* mempool for output */ struct kmem_cache *cache; /* cache for buffers */ + atomic64_t corrected; /* corrected errors */ }; /* per-bio data */ @@ -68,8 +65,8 @@ struct dm_verity_fec_io { extern bool verity_fec_is_enabled(struct dm_verity *v); extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, - enum verity_block_type type, sector_t block, - u8 *dest); + enum verity_block_type type, const u8 *want_digest, + sector_t block, u8 *dest); extern unsigned int verity_fec_status_table(struct dm_verity *v, unsigned int sz, char *result, unsigned int maxlen); @@ -99,6 +96,7 @@ static inline bool verity_fec_is_enabled(struct dm_verity *v) static inline int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, enum verity_block_type type, + const u8 *want_digest, sector_t block, u8 *dest) { return -EOPNOTSUPP; diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 66a00a8ccb39..5c17472d7896 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -117,11 +117,25 @@ static sector_t verity_position_at_level(struct dm_verity *v, sector_t block, int verity_hash(struct dm_verity *v, struct dm_verity_io *io, const u8 *data, size_t len, u8 *digest) { - struct shash_desc *desc = &io->hash_desc; + struct shash_desc *desc; int r; + if (likely(v->use_sha256_lib)) { + struct sha256_ctx *ctx = &io->hash_ctx.sha256; + + /* + * Fast path using SHA-256 library. This is enabled only for + * verity version 1, where the salt is at the beginning. + */ + *ctx = *v->initial_hashstate.sha256; + sha256_update(ctx, data, len); + sha256_final(ctx, digest); + return 0; + } + + desc = &io->hash_ctx.shash; desc->tfm = v->shash_tfm; - if (unlikely(v->initial_hashstate == NULL)) { + if (unlikely(v->initial_hashstate.shash == NULL)) { /* Version 0: salt at end */ r = crypto_shash_init(desc) ?: crypto_shash_update(desc, data, len) ?: @@ -129,7 +143,7 @@ int verity_hash(struct dm_verity *v, struct dm_verity_io *io, crypto_shash_final(desc, digest); } else { /* Version 1: salt at beginning */ - r = crypto_shash_import(desc, v->initial_hashstate) ?: + r = crypto_shash_import(desc, v->initial_hashstate.shash) ?: crypto_shash_finup(desc, data, len, digest); } if (unlikely(r)) @@ -215,12 +229,12 @@ out: * Verify hash of a metadata block pertaining to the specified data block * ("block" argument) at a specified level ("level" argument). * - * On successful return, verity_io_want_digest(v, io) contains the hash value - * for a lower tree level or for the data block (if we're at the lowest level). + * On successful return, want_digest contains the hash value for a lower tree + * level or for the data block (if we're at the lowest level). * * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned. * If "skip_unverified" is false, unverified buffer is hashed and verified - * against current value of verity_io_want_digest(v, io). + * against current value of want_digest. */ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io, sector_t block, int level, bool skip_unverified, @@ -259,7 +273,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io, if (IS_ERR(data)) return r; if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_METADATA, - hash_block, data) == 0) { + want_digest, hash_block, data) == 0) { aux = dm_bufio_get_aux_data(buf); aux->hash_verified = 1; goto release_ok; @@ -279,11 +293,11 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io, } r = verity_hash(v, io, data, 1 << v->hash_dev_block_bits, - verity_io_real_digest(v, io)); + io->tmp_digest); if (unlikely(r < 0)) goto release_ret_r; - if (likely(memcmp(verity_io_real_digest(v, io), want_digest, + if (likely(memcmp(io->tmp_digest, want_digest, v->digest_size) == 0)) aux->hash_verified = 1; else if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) { @@ -294,7 +308,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io, r = -EAGAIN; goto release_ret_r; } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_METADATA, - hash_block, data) == 0) + want_digest, hash_block, data) == 0) aux->hash_verified = 1; else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA, @@ -358,7 +372,8 @@ out: } static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io, - sector_t cur_block, u8 *dest) + const u8 *want_digest, sector_t cur_block, + u8 *dest) { struct page *page; void *buffer; @@ -382,12 +397,11 @@ static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io, goto free_ret; r = verity_hash(v, io, buffer, 1 << v->data_dev_block_bits, - verity_io_real_digest(v, io)); + io->tmp_digest); if (unlikely(r)) goto free_ret; - if (memcmp(verity_io_real_digest(v, io), - verity_io_want_digest(v, io), v->digest_size)) { + if (memcmp(io->tmp_digest, want_digest, v->digest_size)) { r = -EIO; goto free_ret; } @@ -402,9 +416,13 @@ free_ret: static int verity_handle_data_hash_mismatch(struct dm_verity *v, struct dm_verity_io *io, - struct bio *bio, sector_t blkno, - u8 *data) + struct bio *bio, + struct pending_block *block) { + const u8 *want_digest = block->want_digest; + sector_t blkno = block->blkno; + u8 *data = block->data; + if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) { /* * Error handling code (FEC included) cannot be run in the @@ -412,14 +430,14 @@ static int verity_handle_data_hash_mismatch(struct dm_verity *v, */ return -EAGAIN; } - if (verity_recheck(v, io, blkno, data) == 0) { + if (verity_recheck(v, io, want_digest, blkno, data) == 0) { if (v->validated_blocks) set_bit(blkno, v->validated_blocks); return 0; } #if defined(CONFIG_DM_VERITY_FEC) - if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, blkno, - data) == 0) + if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, want_digest, + blkno, data) == 0) return 0; #endif if (bio->bi_status) @@ -433,6 +451,58 @@ static int verity_handle_data_hash_mismatch(struct dm_verity *v, return 0; } +static void verity_clear_pending_blocks(struct dm_verity_io *io) +{ + int i; + + for (i = io->num_pending - 1; i >= 0; i--) { + kunmap_local(io->pending_blocks[i].data); + io->pending_blocks[i].data = NULL; + } + io->num_pending = 0; +} + +static int verity_verify_pending_blocks(struct dm_verity *v, + struct dm_verity_io *io, + struct bio *bio) +{ + const unsigned int block_size = 1 << v->data_dev_block_bits; + int i, r; + + if (io->num_pending == 2) { + /* num_pending == 2 implies that the algorithm is SHA-256 */ + sha256_finup_2x(v->initial_hashstate.sha256, + io->pending_blocks[0].data, + io->pending_blocks[1].data, block_size, + io->pending_blocks[0].real_digest, + io->pending_blocks[1].real_digest); + } else { + for (i = 0; i < io->num_pending; i++) { + r = verity_hash(v, io, io->pending_blocks[i].data, + block_size, + io->pending_blocks[i].real_digest); + if (unlikely(r)) + return r; + } + } + + for (i = 0; i < io->num_pending; i++) { + struct pending_block *block = &io->pending_blocks[i]; + + if (likely(memcmp(block->real_digest, block->want_digest, + v->digest_size) == 0)) { + if (v->validated_blocks) + set_bit(block->blkno, v->validated_blocks); + } else { + r = verity_handle_data_hash_mismatch(v, io, bio, block); + if (unlikely(r)) + return r; + } + } + verity_clear_pending_blocks(io); + return 0; +} + /* * Verify one "dm_verity_io" structure. */ @@ -440,10 +510,14 @@ static int verity_verify_io(struct dm_verity_io *io) { struct dm_verity *v = io->v; const unsigned int block_size = 1 << v->data_dev_block_bits; + const int max_pending = v->use_sha256_finup_2x ? 2 : 1; struct bvec_iter iter_copy; struct bvec_iter *iter; struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size); unsigned int b; + int r; + + io->num_pending = 0; if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) { /* @@ -457,21 +531,22 @@ static int verity_verify_io(struct dm_verity_io *io) for (b = 0; b < io->n_blocks; b++, bio_advance_iter(bio, iter, block_size)) { - int r; - sector_t cur_block = io->block + b; + sector_t blkno = io->block + b; + struct pending_block *block; bool is_zero; struct bio_vec bv; void *data; if (v->validated_blocks && bio->bi_status == BLK_STS_OK && - likely(test_bit(cur_block, v->validated_blocks))) + likely(test_bit(blkno, v->validated_blocks))) continue; - r = verity_hash_for_block(v, io, cur_block, - verity_io_want_digest(v, io), + block = &io->pending_blocks[io->num_pending]; + + r = verity_hash_for_block(v, io, blkno, block->want_digest, &is_zero); if (unlikely(r < 0)) - return r; + goto error; bv = bio_iter_iovec(bio, *iter); if (unlikely(bv.bv_len < block_size)) { @@ -482,7 +557,8 @@ static int verity_verify_io(struct dm_verity_io *io) * data block size to be greater than PAGE_SIZE. */ DMERR_LIMIT("unaligned io (data block spans pages)"); - return -EIO; + r = -EIO; + goto error; } data = bvec_kmap_local(&bv); @@ -496,29 +572,26 @@ static int verity_verify_io(struct dm_verity_io *io) kunmap_local(data); continue; } - - r = verity_hash(v, io, data, block_size, - verity_io_real_digest(v, io)); - if (unlikely(r < 0)) { - kunmap_local(data); - return r; + block->data = data; + block->blkno = blkno; + if (++io->num_pending == max_pending) { + r = verity_verify_pending_blocks(v, io, bio); + if (unlikely(r)) + goto error; } + } - if (likely(memcmp(verity_io_real_digest(v, io), - verity_io_want_digest(v, io), v->digest_size) == 0)) { - if (v->validated_blocks) - set_bit(cur_block, v->validated_blocks); - kunmap_local(data); - continue; - } - r = verity_handle_data_hash_mismatch(v, io, bio, cur_block, - data); - kunmap_local(data); + if (io->num_pending) { + r = verity_verify_pending_blocks(v, io, bio); if (unlikely(r)) - return r; + goto error; } return 0; + +error: + verity_clear_pending_blocks(io); + return r; } /* @@ -775,6 +848,10 @@ static void verity_status(struct dm_target *ti, status_type_t type, switch (type) { case STATUSTYPE_INFO: DMEMIT("%c", v->hash_failed ? 'C' : 'V'); + if (verity_fec_is_enabled(v)) + DMEMIT(" %lld", atomic64_read(&v->fec->corrected)); + else + DMEMIT(" -"); break; case STATUSTYPE_TABLE: DMEMIT("%u %s %s %u %u %llu %llu %s ", @@ -1004,7 +1081,7 @@ static void verity_dtr(struct dm_target *ti) kvfree(v->validated_blocks); kfree(v->salt); - kfree(v->initial_hashstate); + kfree(v->initial_hashstate.shash); kfree(v->root_digest); kfree(v->zero_digest); verity_free_sig(v); @@ -1069,8 +1146,7 @@ static int verity_alloc_zero_digest(struct dm_verity *v) if (!v->zero_digest) return r; - io = kmalloc(sizeof(*io) + crypto_shash_descsize(v->shash_tfm), - GFP_KERNEL); + io = kmalloc(v->ti->per_io_data_size, GFP_KERNEL); if (!io) return r; /* verity_dtr will free zero_digest */ @@ -1252,11 +1328,26 @@ static int verity_setup_hash_alg(struct dm_verity *v, const char *alg_name) } v->shash_tfm = shash; v->digest_size = crypto_shash_digestsize(shash); - DMINFO("%s using \"%s\"", alg_name, crypto_shash_driver_name(shash)); if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) { ti->error = "Digest size too big"; return -EINVAL; } + if (likely(v->version && strcmp(alg_name, "sha256") == 0)) { + /* + * Fast path: use the library API for reduced overhead and + * interleaved hashing support. + */ + v->use_sha256_lib = true; + if (sha256_finup_2x_is_optimized()) + v->use_sha256_finup_2x = true; + ti->per_io_data_size = + offsetofend(struct dm_verity_io, hash_ctx.sha256); + } else { + /* Fallback case: use the generic crypto API. */ + ti->per_io_data_size = + offsetofend(struct dm_verity_io, hash_ctx.shash) + + crypto_shash_descsize(shash); + } return 0; } @@ -1277,7 +1368,18 @@ static int verity_setup_salt_and_hashstate(struct dm_verity *v, const char *arg) return -EINVAL; } } - if (v->version) { /* Version 1: salt at beginning */ + if (likely(v->use_sha256_lib)) { + /* Implies version 1: salt at beginning */ + v->initial_hashstate.sha256 = + kmalloc(sizeof(struct sha256_ctx), GFP_KERNEL); + if (!v->initial_hashstate.sha256) { + ti->error = "Cannot allocate initial hash state"; + return -ENOMEM; + } + sha256_init(v->initial_hashstate.sha256); + sha256_update(v->initial_hashstate.sha256, + v->salt, v->salt_size); + } else if (v->version) { /* Version 1: salt at beginning */ SHASH_DESC_ON_STACK(desc, v->shash_tfm); int r; @@ -1285,16 +1387,16 @@ static int verity_setup_salt_and_hashstate(struct dm_verity *v, const char *arg) * Compute the pre-salted hash state that can be passed to * crypto_shash_import() for each block later. */ - v->initial_hashstate = kmalloc( + v->initial_hashstate.shash = kmalloc( crypto_shash_statesize(v->shash_tfm), GFP_KERNEL); - if (!v->initial_hashstate) { + if (!v->initial_hashstate.shash) { ti->error = "Cannot allocate initial hash state"; return -ENOMEM; } desc->tfm = v->shash_tfm; r = crypto_shash_init(desc) ?: crypto_shash_update(desc, v->salt, v->salt_size) ?: - crypto_shash_export(desc, v->initial_hashstate); + crypto_shash_export(desc, v->initial_hashstate.shash); if (r) { ti->error = "Cannot set up initial hash state"; return r; @@ -1556,9 +1658,6 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad; } - ti->per_io_data_size = sizeof(struct dm_verity_io) + - crypto_shash_descsize(v->shash_tfm); - r = verity_fec_ctr(v); if (r) goto bad; @@ -1690,7 +1789,7 @@ static struct target_type verity_target = { .name = "verity", /* Note: the LSMs depend on the singleton and immutable features */ .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE, - .version = {1, 12, 0}, + .version = {1, 13, 0}, .module = THIS_MODULE, .ctr = verity_ctr, .dtr = verity_dtr, diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h index 6d141abd965c..f975a9e5c5d6 100644 --- a/drivers/md/dm-verity.h +++ b/drivers/md/dm-verity.h @@ -16,6 +16,7 @@ #include <linux/device-mapper.h> #include <linux/interrupt.h> #include <crypto/hash.h> +#include <crypto/sha2.h> #define DM_VERITY_MAX_LEVELS 63 @@ -42,7 +43,10 @@ struct dm_verity { struct crypto_shash *shash_tfm; u8 *root_digest; /* digest of the root block */ u8 *salt; /* salt: its size is salt_size */ - u8 *initial_hashstate; /* salted initial state, if version >= 1 */ + union { + struct sha256_ctx *sha256; /* for use_sha256_lib=1 */ + u8 *shash; /* for use_sha256_lib=0 */ + } initial_hashstate; /* salted initial state, if version >= 1 */ u8 *zero_digest; /* digest for a zero block */ #ifdef CONFIG_SECURITY u8 *root_digest_sig; /* signature of the root digest */ @@ -59,6 +63,8 @@ struct dm_verity { unsigned char version; bool hash_failed:1; /* set if hash of any block failed */ bool use_bh_wq:1; /* try to verify in BH wq before normal work-queue */ + bool use_sha256_lib:1; /* use SHA-256 library instead of generic crypto API */ + bool use_sha256_finup_2x:1; /* use interleaved hashing optimization */ unsigned int digest_size; /* digest size for the current hash algorithm */ enum verity_mode mode; /* mode for handling verification errors */ enum verity_mode error_mode;/* mode for handling I/O errors */ @@ -78,6 +84,13 @@ struct dm_verity { mempool_t recheck_pool; }; +struct pending_block { + void *data; + sector_t blkno; + u8 want_digest[HASH_MAX_DIGESTSIZE]; + u8 real_digest[HASH_MAX_DIGESTSIZE]; +}; + struct dm_verity_io { struct dm_verity *v; @@ -94,28 +107,29 @@ struct dm_verity_io { struct work_struct work; struct work_struct bh_work; - u8 real_digest[HASH_MAX_DIGESTSIZE]; - u8 want_digest[HASH_MAX_DIGESTSIZE]; + u8 tmp_digest[HASH_MAX_DIGESTSIZE]; /* - * Temporary space for hashing. This is variable-length and must be at - * the end of the struct. struct shash_desc is just the fixed part; - * it's followed by a context of size crypto_shash_descsize(shash_tfm). + * This is the queue of data blocks that are pending verification. When + * the crypto layer supports interleaved hashing, we allow multiple + * blocks to be queued up in order to utilize it. This can improve + * performance significantly vs. sequential hashing of each block. */ - struct shash_desc hash_desc; -}; + int num_pending; + struct pending_block pending_blocks[2]; -static inline u8 *verity_io_real_digest(struct dm_verity *v, - struct dm_verity_io *io) -{ - return io->real_digest; -} - -static inline u8 *verity_io_want_digest(struct dm_verity *v, - struct dm_verity_io *io) -{ - return io->want_digest; -} + /* + * Temporary space for hashing. Either sha256 or shash is used, + * depending on the value of use_sha256_lib. If shash is used, + * then this field is variable-length, with total size + * sizeof(struct shash_desc) + crypto_shash_descsize(shash_tfm). + * For this reason, this field must be the end of the struct. + */ + union { + struct sha256_ctx sha256; + struct shash_desc shash; + } hash_ctx; +}; extern int verity_hash(struct dm_verity *v, struct dm_verity_io *io, const u8 *data, size_t len, u8 *digest); diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c index 5a840c4ae316..c95e417194b3 100644 --- a/drivers/md/dm-zone.c +++ b/drivers/md/dm-zone.c @@ -203,8 +203,6 @@ int dm_revalidate_zones(struct dm_table *t, struct request_queue *q) return ret; } - md->nr_zones = disk->nr_zones; - return 0; } @@ -452,7 +450,6 @@ void dm_finalize_zone_settings(struct dm_table *t, struct queue_limits *lim) set_bit(DMF_EMULATE_ZONE_APPEND, &md->flags); } else { clear_bit(DMF_EMULATE_ZONE_APPEND, &md->flags); - md->nr_zones = 0; md->disk->nr_zones = 0; } } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6c83ab940af7..b63279202260 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -272,7 +272,7 @@ static int __init dm_init(void) int r, i; #if (IS_ENABLED(CONFIG_IMA) && !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) - DMWARN("CONFIG_IMA_DISABLE_HTABLE is disabled." + DMINFO("CONFIG_IMA_DISABLE_HTABLE is disabled." " Duplicate IMA measurements will not be recorded in the IMA log."); #endif @@ -1321,6 +1321,7 @@ void dm_accept_partial_bio(struct bio *bio, unsigned int n_sectors) BUG_ON(dm_tio_flagged(tio, DM_TIO_IS_DUPLICATE_BIO)); BUG_ON(bio_sectors > *tio->len_ptr); BUG_ON(n_sectors > bio_sectors); + BUG_ON(bio->bi_opf & REQ_ATOMIC); if (static_branch_unlikely(&zoned_enabled) && unlikely(bdev_is_zoned(bio->bi_bdev))) { @@ -1735,8 +1736,12 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci) ci->submit_as_polled = !!(ci->bio->bi_opf & REQ_POLLED); len = min_t(sector_t, max_io_len(ti, ci->sector), ci->sector_count); - if (ci->bio->bi_opf & REQ_ATOMIC && len != ci->sector_count) - return BLK_STS_IOERR; + if (ci->bio->bi_opf & REQ_ATOMIC) { + if (unlikely(!dm_target_supports_atomic_writes(ti->type))) + return BLK_STS_IOERR; + if (unlikely(len != ci->sector_count)) + return BLK_STS_IOERR; + } setup_split_accounting(ci, len); @@ -2439,7 +2444,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t, { struct dm_table *old_map; sector_t size, old_size; - int ret; lockdep_assert_held(&md->suspend_lock); @@ -2454,11 +2458,13 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t, set_capacity(md->disk, size); - ret = dm_table_set_restrictions(t, md->queue, limits); - if (ret) { - set_capacity(md->disk, old_size); - old_map = ERR_PTR(ret); - goto out; + if (limits) { + int ret = dm_table_set_restrictions(t, md->queue, limits); + if (ret) { + set_capacity(md->disk, old_size); + old_map = ERR_PTR(ret); + goto out; + } } /* @@ -2836,6 +2842,7 @@ static void dm_wq_work(struct work_struct *work) static void dm_queue_flush(struct mapped_device *md) { + clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); clear_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags); smp_mb__after_atomic(); queue_work(md->wq, &md->work); @@ -2848,6 +2855,7 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) { struct dm_table *live_map = NULL, *map = ERR_PTR(-EINVAL); struct queue_limits limits; + bool update_limits = true; int r; mutex_lock(&md->suspend_lock); @@ -2857,19 +2865,30 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) goto out; /* + * To avoid a potential deadlock locking the queue limits, disallow + * updating the queue limits during a table swap, when updating an + * immutable request-based dm device (dm-multipath) during a noflush + * suspend. It is userspace's responsibility to make sure that the new + * table uses the same limits as the existing table, if it asks for a + * noflush suspend. + */ + if (dm_request_based(md) && md->immutable_target && + __noflush_suspending(md)) + update_limits = false; + /* * If the new table has no data devices, retain the existing limits. * This helps multipath with queue_if_no_path if all paths disappear, * then new I/O is queued based on these limits, and then some paths * reappear. */ - if (dm_table_has_no_data_devices(table)) { + else if (dm_table_has_no_data_devices(table)) { live_map = dm_get_live_table_fast(md); if (live_map) limits = md->queue->limits; dm_put_live_table_fast(md); } - if (!live_map) { + if (update_limits && !live_map) { r = dm_calculate_queue_limits(table, &limits); if (r) { map = ERR_PTR(r); @@ -2877,7 +2896,7 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) } } - map = __bind(md, table, &limits); + map = __bind(md, table, update_limits ? &limits : NULL); dm_issue_global_event(); out: @@ -2930,7 +2949,6 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map, /* * DMF_NOFLUSH_SUSPENDING must be set before presuspend. - * This flag is cleared before dm_suspend returns. */ if (noflush) set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); @@ -2993,8 +3011,6 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map, if (!r) set_bit(dmf_suspended_flag, &md->flags); - if (noflush) - clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); if (map) synchronize_srcu(&md->io_barrier); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 9d1de68dee27..d7d41b054b98 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -106,7 +106,6 @@ config PHANTOM config RPMB tristate "RPMB partition interface" - depends on MMC || SCSI_UFSHCD help Unified RPMB unit interface for RPMB capable devices such as eMMC and UFS. Provides interface for in-kernel security controllers to access diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index adc47b87b38a..884171871d0e 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -1600,7 +1600,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) err = ubi_read_volume_table(ubi, ai); if (err) - goto out_ai; + goto out_fm; err = ubi_wl_init(ubi, ai); if (err) @@ -1642,6 +1642,8 @@ out_wl: out_vtbl: ubi_free_all_volumes(ubi); vfree(ubi->vtbl); +out_fm: + ubi_free_fastmap(ubi); out_ai: destroy_ai(ai); return err; diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 9bdb6525f128..e2bc1122bfd3 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -530,8 +530,6 @@ int ubi_is_erase_work(struct ubi_work *wrk) static void ubi_fastmap_close(struct ubi_device *ubi) { - int i; - return_unused_pool_pebs(ubi, &ubi->fm_pool); return_unused_pool_pebs(ubi, &ubi->fm_wl_pool); @@ -540,11 +538,7 @@ static void ubi_fastmap_close(struct ubi_device *ubi) ubi->fm_anchor = NULL; } - if (ubi->fm) { - for (i = 0; i < ubi->fm->used_blocks; i++) - kfree(ubi->fm->e[i]); - } - kfree(ubi->fm); + ubi_free_fastmap(ubi); } /** diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index a4999bce435f..915eb64cb001 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -868,6 +868,8 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, return -EROFS; } + memset((char *)ec_hdr + UBI_EC_HDR_SIZE, 0xFF, ubi->ec_hdr_alsize - UBI_EC_HDR_SIZE); + err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize); return err; } @@ -1150,6 +1152,14 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, return -EROFS; } + if (ubi->vid_hdr_shift) { + memset((char *)p, 0xFF, ubi->vid_hdr_shift); + memset((char *)p + ubi->vid_hdr_shift + UBI_VID_HDR_SIZE, 0xFF, + ubi->vid_hdr_alsize - (ubi->vid_hdr_shift + UBI_VID_HDR_SIZE)); + } else { + memset((char *)p + UBI_VID_HDR_SIZE, 0xFF, ubi->vid_hdr_alsize - UBI_VID_HDR_SIZE); + } + err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); return err; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index c792b9bcab9b..44803d3329f4 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -969,10 +969,22 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, struct ubi_attach_info *scan_ai); int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count); void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol); +static inline void ubi_free_fastmap(struct ubi_device *ubi) +{ + if (ubi->fm) { + int i; + + for (i = 0; i < ubi->fm->used_blocks; i++) + kmem_cache_free(ubi_wl_entry_slab, ubi->fm->e[i]); + kfree(ubi->fm); + ubi->fm = NULL; + } +} #else static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; } static inline int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) { return 0; } static inline void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) {} +static inline void ubi_free_fastmap(struct ubi_device *ubi) { } #endif /* block.c */ diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c index a01178caf15b..8f3ccb317e4d 100644 --- a/drivers/nvme/host/auth.c +++ b/drivers/nvme/host/auth.c @@ -1122,7 +1122,7 @@ void nvme_auth_free(struct nvme_ctrl *ctrl) if (ctrl->dhchap_ctxs) { for (i = 0; i < ctrl_max_dhchaps(ctrl); i++) nvme_auth_free_dhchap(&ctrl->dhchap_ctxs[i]); - kfree(ctrl->dhchap_ctxs); + kvfree(ctrl->dhchap_ctxs); } if (ctrl->host_key) { nvme_auth_free_key(ctrl->host_key); diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 2e58a7ce1090..55a8afd2efd5 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -592,7 +592,7 @@ bool nvmf_should_reconnect(struct nvme_ctrl *ctrl, int status) if (status > 0 && (status & NVME_STATUS_DNR)) return false; - if (status == -EKEYREJECTED) + if (status == -EKEYREJECTED || status == -ENOKEY) return false; if (ctrl->opts->max_reconnects == -1 || diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 873954d43b18..bc455fa98246 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -520,6 +520,8 @@ nvme_fc_free_rport(struct kref *ref) WARN_ON(rport->remoteport.port_state != FC_OBJSTATE_DELETED); WARN_ON(!list_empty(&rport->ctrl_list)); + WARN_ON(!list_empty(&rport->ls_req_list)); + WARN_ON(!list_empty(&rport->ls_rcv_list)); /* remove from lport list */ spin_lock_irqsave(&nvme_fc_lock, flags); @@ -1468,14 +1470,14 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport, { struct fcnvme_ls_disconnect_assoc_rqst *rqst = &lsop->rqstbuf->rq_dis_assoc; - struct nvme_fc_ctrl *ctrl, *ret = NULL; + struct nvme_fc_ctrl *ctrl, *tmp, *ret = NULL; struct nvmefc_ls_rcv_op *oldls = NULL; u64 association_id = be64_to_cpu(rqst->associd.association_id); unsigned long flags; spin_lock_irqsave(&rport->lock, flags); - list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) { + list_for_each_entry_safe(ctrl, tmp, &rport->ctrl_list, ctrl_list) { if (!nvme_fc_ctrl_get(ctrl)) continue; spin_lock(&ctrl->lock); @@ -1488,7 +1490,9 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport, if (ret) /* leave the ctrl get reference */ break; + spin_unlock_irqrestore(&rport->lock, flags); nvme_fc_ctrl_put(ctrl); + spin_lock_irqsave(&rport->lock, flags); } spin_unlock_irqrestore(&rport->lock, flags); diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index 4fa8400a5627..a9c097dacad6 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -447,7 +447,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, struct iov_iter iter; struct iov_iter *map_iter = NULL; struct request *req; - blk_opf_t rq_flags = REQ_ALLOC_CACHE; + blk_opf_t rq_flags = 0; blk_mq_req_flags_t blk_flags = 0; int ret; diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index e5ca8301bb8b..0e4caeab739c 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2984,6 +2984,7 @@ static int nvme_pci_enable(struct nvme_dev *dev) pci_set_master(pdev); if (readl(dev->bar + NVME_REG_CSTS) == -1) { + dev_dbg(dev->ctrl.device, "reading CSTS register failed\n"); result = -ENODEV; goto disable; } @@ -3609,6 +3610,7 @@ out_uninit_ctrl: nvme_uninit_ctrl(&dev->ctrl); out_put_ctrl: nvme_put_ctrl(&dev->ctrl); + dev_err_probe(&pdev->dev, result, "probe failed\n"); return result; } diff --git a/drivers/nvme/host/pr.c b/drivers/nvme/host/pr.c index ca6a74607b13..ad2ecc2f49a9 100644 --- a/drivers/nvme/host/pr.c +++ b/drivers/nvme/host/pr.c @@ -228,7 +228,8 @@ retry: static int nvme_pr_read_keys(struct block_device *bdev, struct pr_keys *keys_info) { - u32 rse_len, num_keys = keys_info->num_keys; + size_t rse_len; + u32 num_keys = keys_info->num_keys; struct nvme_reservation_status_ext *rse; int ret, i; bool eds; @@ -238,6 +239,9 @@ static int nvme_pr_read_keys(struct block_device *bdev, * enough to get enough keys to fill the return keys buffer. */ rse_len = struct_size(rse, regctl_eds, num_keys); + if (rse_len > U32_MAX) + return -EINVAL; + rse = kzalloc(rse_len, GFP_KERNEL); if (!rse) return -ENOMEM; diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 3e378153a781..3da31bb1183e 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -708,7 +708,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) /* * We don't really have a practical limit on the number of abort - * comands. But we don't do anything useful for abort either, so + * commands. But we don't do anything useful for abort either, so * no point in allowing more abort commands than the spec requires. */ id->acl = 3; diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c index 300d5e032f6d..2eadeb7e06f2 100644 --- a/drivers/nvme/target/auth.c +++ b/drivers/nvme/target/auth.c @@ -381,8 +381,8 @@ int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response, ret = crypto_shash_update(shash, buf, 1); if (ret) goto out; - ret = crypto_shash_update(shash, ctrl->subsysnqn, - strlen(ctrl->subsysnqn)); + ret = crypto_shash_update(shash, ctrl->subsys->subsysnqn, + strlen(ctrl->subsys->subsysnqn)); if (ret) goto out; ret = crypto_shash_final(shash, response); @@ -429,7 +429,7 @@ int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, } transformed_key = nvme_auth_transform_key(ctrl->ctrl_key, - ctrl->subsysnqn); + ctrl->subsys->subsysnqn); if (IS_ERR(transformed_key)) { ret = PTR_ERR(transformed_key); goto out_free_tfm; @@ -484,8 +484,8 @@ int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, ret = crypto_shash_update(shash, "Controller", 10); if (ret) goto out; - ret = crypto_shash_update(shash, ctrl->subsysnqn, - strlen(ctrl->subsysnqn)); + ret = crypto_shash_update(shash, ctrl->subsys->subsysnqn, + strlen(ctrl->subsys->subsysnqn)); if (ret) goto out; ret = crypto_shash_update(shash, buf, 1); @@ -575,7 +575,7 @@ void nvmet_auth_insert_psk(struct nvmet_sq *sq) return; } ret = nvme_auth_generate_digest(sq->ctrl->shash_id, psk, psk_len, - sq->ctrl->subsysnqn, + sq->ctrl->subsys->subsysnqn, sq->ctrl->hostnqn, &digest); if (ret) { pr_warn("%s: ctrl %d qid %d failed to generate digest, error %d\n", @@ -590,8 +590,10 @@ void nvmet_auth_insert_psk(struct nvmet_sq *sq) goto out_free_digest; } #ifdef CONFIG_NVME_TARGET_TCP_TLS - tls_key = nvme_tls_psk_refresh(NULL, sq->ctrl->hostnqn, sq->ctrl->subsysnqn, - sq->ctrl->shash_id, tls_psk, psk_len, digest); + tls_key = nvme_tls_psk_refresh(NULL, sq->ctrl->hostnqn, + sq->ctrl->subsys->subsysnqn, + sq->ctrl->shash_id, tls_psk, psk_len, + digest); if (IS_ERR(tls_key)) { pr_warn("%s: ctrl %d qid %d failed to refresh key, error %ld\n", __func__, sq->ctrl->cntlid, sq->qid, PTR_ERR(tls_key)); diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 5d7d483bfbe3..cc88e5a28c8a 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -40,7 +40,7 @@ EXPORT_SYMBOL_GPL(nvmet_wq); * - the nvmet_transports array * * When updating any of those lists/structures write lock should be obtained, - * while when reading (popolating discovery log page or checking host-subsystem + * while when reading (populating discovery log page or checking host-subsystem * link) read lock is obtained to allow concurrent reads. */ DECLARE_RWSEM(nvmet_config_sem); @@ -1628,7 +1628,6 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler); INIT_DELAYED_WORK(&ctrl->ka_work, nvmet_keep_alive_timer); - memcpy(ctrl->subsysnqn, args->subsysnqn, NVMF_NQN_SIZE); memcpy(ctrl->hostnqn, args->hostnqn, NVMF_NQN_SIZE); kref_init(&ctrl->ref); @@ -1903,6 +1902,8 @@ static void nvmet_subsys_free(struct kref *ref) struct nvmet_subsys *subsys = container_of(ref, struct nvmet_subsys, ref); + WARN_ON_ONCE(!list_empty(&subsys->ctrls)); + WARN_ON_ONCE(!list_empty(&subsys->hosts)); WARN_ON_ONCE(!xa_empty(&subsys->namespaces)); nvmet_debugfs_subsys_free(subsys); diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 7d84527d5a43..0d9784004c9b 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -490,8 +490,7 @@ nvmet_fc_xmt_disconnect_assoc(struct nvmet_fc_tgt_assoc *assoc) sizeof(*discon_rqst) + sizeof(*discon_acc) + tgtport->ops->lsrqst_priv_sz), GFP_KERNEL); if (!lsop) { - dev_info(tgtport->dev, - "{%d:%d} send Disconnect Association failed: ENOMEM\n", + pr_info("{%d:%d}: send Disconnect Association failed: ENOMEM\n", tgtport->fc_target_port.port_num, assoc->a_id); return; } @@ -513,8 +512,7 @@ nvmet_fc_xmt_disconnect_assoc(struct nvmet_fc_tgt_assoc *assoc) ret = nvmet_fc_send_ls_req_async(tgtport, lsop, nvmet_fc_disconnect_assoc_done); if (ret) { - dev_info(tgtport->dev, - "{%d:%d} XMT Disconnect Association failed: %d\n", + pr_info("{%d:%d}: XMT Disconnect Association failed: %d\n", tgtport->fc_target_port.port_num, assoc->a_id, ret); kfree(lsop); } @@ -1187,8 +1185,7 @@ nvmet_fc_target_assoc_free(struct kref *ref) if (oldls) nvmet_fc_xmt_ls_rsp(tgtport, oldls); ida_free(&tgtport->assoc_cnt, assoc->a_id); - dev_info(tgtport->dev, - "{%d:%d} Association freed\n", + pr_info("{%d:%d}: Association freed\n", tgtport->fc_target_port.port_num, assoc->a_id); kfree(assoc); } @@ -1224,8 +1221,7 @@ nvmet_fc_delete_target_assoc(struct nvmet_fc_tgt_assoc *assoc) flush_workqueue(assoc->queues[i]->work_q); } - dev_info(tgtport->dev, - "{%d:%d} Association deleted\n", + pr_info("{%d:%d}: Association deleted\n", tgtport->fc_target_port.port_num, assoc->a_id); nvmet_fc_tgtport_put(tgtport); @@ -1716,9 +1712,9 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, } if (ret) { - dev_err(tgtport->dev, - "Create Association LS failed: %s\n", - validation_errors[ret]); + pr_err("{%d}: Create Association LS failed: %s\n", + tgtport->fc_target_port.port_num, + validation_errors[ret]); iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, sizeof(*acc), rqst->w0.ls_cmd, FCNVME_RJT_RC_LOGIC, @@ -1730,8 +1726,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, atomic_set(&queue->connected, 1); queue->sqhd = 0; /* best place to init value */ - dev_info(tgtport->dev, - "{%d:%d} Association created\n", + pr_info("{%d:%d}: Association created\n", tgtport->fc_target_port.port_num, iod->assoc->a_id); /* format a response */ @@ -1809,9 +1804,9 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, } if (ret) { - dev_err(tgtport->dev, - "Create Connection LS failed: %s\n", - validation_errors[ret]); + pr_err("{%d}: Create Connection LS failed: %s\n", + tgtport->fc_target_port.port_num, + validation_errors[ret]); iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, sizeof(*acc), rqst->w0.ls_cmd, (ret == VERR_NO_ASSOC) ? @@ -1871,9 +1866,9 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, } if (ret || !assoc) { - dev_err(tgtport->dev, - "Disconnect LS failed: %s\n", - validation_errors[ret]); + pr_err("{%d}: Disconnect LS failed: %s\n", + tgtport->fc_target_port.port_num, + validation_errors[ret]); iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, sizeof(*acc), rqst->w0.ls_cmd, (ret == VERR_NO_ASSOC) ? @@ -1907,8 +1902,7 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, spin_unlock_irqrestore(&tgtport->lock, flags); if (oldls) { - dev_info(tgtport->dev, - "{%d:%d} Multiple Disconnect Association LS's " + pr_info("{%d:%d}: Multiple Disconnect Association LS's " "received\n", tgtport->fc_target_port.port_num, assoc->a_id); /* overwrite good response with bogus failure */ @@ -2051,8 +2045,8 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, struct fcnvme_ls_rqst_w0 *w0 = (struct fcnvme_ls_rqst_w0 *)lsreqbuf; if (lsreqbuf_len > sizeof(union nvmefc_ls_requests)) { - dev_info(tgtport->dev, - "RCV %s LS failed: payload too large (%d)\n", + pr_info("{%d}: RCV %s LS failed: payload too large (%d)\n", + tgtport->fc_target_port.port_num, (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? nvmefc_ls_names[w0->ls_cmd] : "", lsreqbuf_len); @@ -2060,8 +2054,8 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, } if (!nvmet_fc_tgtport_get(tgtport)) { - dev_info(tgtport->dev, - "RCV %s LS failed: target deleting\n", + pr_info("{%d}: RCV %s LS failed: target deleting\n", + tgtport->fc_target_port.port_num, (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? nvmefc_ls_names[w0->ls_cmd] : ""); return -ESHUTDOWN; @@ -2069,8 +2063,8 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, iod = nvmet_fc_alloc_ls_iod(tgtport); if (!iod) { - dev_info(tgtport->dev, - "RCV %s LS failed: context allocation failed\n", + pr_info("{%d}: RCV %s LS failed: context allocation failed\n", + tgtport->fc_target_port.port_num, (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? nvmefc_ls_names[w0->ls_cmd] : ""); nvmet_fc_tgtport_put(tgtport); diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index 5dffcc5becae..c30e9a3e014f 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -254,7 +254,6 @@ struct fcloop_nport { struct fcloop_lsreq { struct nvmefc_ls_req *lsreq; struct nvmefc_ls_rsp ls_rsp; - int lsdir; /* H2T or T2H */ int status; struct list_head ls_list; /* fcloop_rport->ls_list */ }; @@ -1111,8 +1110,10 @@ fcloop_remoteport_delete(struct nvme_fc_remote_port *remoteport) rport->nport->rport = NULL; spin_unlock_irqrestore(&fcloop_lock, flags); - if (put_port) + if (put_port) { + WARN_ON(!list_empty(&rport->ls_list)); fcloop_nport_put(rport->nport); + } } static void @@ -1130,8 +1131,10 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport) tport->nport->tport = NULL; spin_unlock_irqrestore(&fcloop_lock, flags); - if (put_port) + if (put_port) { + WARN_ON(!list_empty(&tport->ls_list)); fcloop_nport_put(tport->nport); + } } #define FCLOOP_HW_QUEUES 4 diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index f3b09f4099f0..b664b584fdc8 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -285,7 +285,6 @@ struct nvmet_ctrl { __le32 *changed_ns_list; u32 nr_changed_ns; - char subsysnqn[NVMF_NQN_FIELD_LEN]; char hostnqn[NVMF_NQN_FIELD_LEN]; struct device *p2p_client; diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index 0c361b1e3566..96648ec2fadb 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -150,7 +150,7 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req) * code path with duplicate ctrl subsysnqn. In order to prevent that we * mask the passthru-ctrl subsysnqn with the target ctrl subsysnqn. */ - memcpy(id->subnqn, ctrl->subsysnqn, sizeof(id->subnqn)); + memcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn)); /* use fabric id-ctrl values */ id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) + diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index 2e78397a7373..f858a6c9d7cb 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -320,12 +320,14 @@ static void nvmet_pci_epf_init_dma(struct nvmet_pci_epf *nvme_epf) nvme_epf->dma_enabled = true; dev_dbg(dev, "Using DMA RX channel %s, maximum segment size %u B\n", - dma_chan_name(chan), - dma_get_max_seg_size(dmaengine_get_dma_device(chan))); + dma_chan_name(nvme_epf->dma_rx_chan), + dma_get_max_seg_size(dmaengine_get_dma_device(nvme_epf-> + dma_rx_chan))); dev_dbg(dev, "Using DMA TX channel %s, maximum segment size %u B\n", - dma_chan_name(chan), - dma_get_max_seg_size(dmaengine_get_dma_device(chan))); + dma_chan_name(nvme_epf->dma_tx_chan), + dma_get_max_seg_size(dmaengine_get_dma_device(nvme_epf-> + dma_tx_chan))); return; @@ -2325,6 +2327,8 @@ static int nvmet_pci_epf_epc_init(struct pci_epf *epf) return ret; } + nvmet_pci_epf_init_dma(nvme_epf); + /* Set device ID, class, etc. */ epf->header->vendorid = ctrl->tctrl->subsys->vendor_id; epf->header->subsys_vendor_id = ctrl->tctrl->subsys->subsys_vendor_id; @@ -2422,8 +2426,6 @@ static int nvmet_pci_epf_bind(struct pci_epf *epf) if (ret) return ret; - nvmet_pci_epf_init_dma(nvme_epf); - return 0; } diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index 0485e25ab797..9c12b2361a6d 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -367,7 +367,7 @@ nvmet_rdma_alloc_cmds(struct nvmet_rdma_device *ndev, struct nvmet_rdma_cmd *cmds; int ret = -EINVAL, i; - cmds = kcalloc(nr_cmds, sizeof(struct nvmet_rdma_cmd), GFP_KERNEL); + cmds = kvcalloc(nr_cmds, sizeof(struct nvmet_rdma_cmd), GFP_KERNEL); if (!cmds) goto out; @@ -382,7 +382,7 @@ nvmet_rdma_alloc_cmds(struct nvmet_rdma_device *ndev, out_free: while (--i >= 0) nvmet_rdma_free_cmd(ndev, cmds + i, admin); - kfree(cmds); + kvfree(cmds); out: return ERR_PTR(ret); } @@ -394,7 +394,7 @@ static void nvmet_rdma_free_cmds(struct nvmet_rdma_device *ndev, for (i = 0; i < nr_cmds; i++) nvmet_rdma_free_cmd(ndev, cmds + i, admin); - kfree(cmds); + kvfree(cmds); } static int nvmet_rdma_alloc_rsp(struct nvmet_rdma_device *ndev, @@ -455,7 +455,7 @@ nvmet_rdma_alloc_rsps(struct nvmet_rdma_queue *queue) NUMA_NO_NODE, false, true)) goto out; - queue->rsps = kcalloc(nr_rsps, sizeof(struct nvmet_rdma_rsp), + queue->rsps = kvcalloc(nr_rsps, sizeof(struct nvmet_rdma_rsp), GFP_KERNEL); if (!queue->rsps) goto out_free_sbitmap; @@ -473,7 +473,7 @@ nvmet_rdma_alloc_rsps(struct nvmet_rdma_queue *queue) out_free: while (--i >= 0) nvmet_rdma_free_rsp(ndev, &queue->rsps[i]); - kfree(queue->rsps); + kvfree(queue->rsps); out_free_sbitmap: sbitmap_free(&queue->rsp_tags); out: @@ -487,7 +487,7 @@ static void nvmet_rdma_free_rsps(struct nvmet_rdma_queue *queue) for (i = 0; i < nr_rsps; i++) nvmet_rdma_free_rsp(ndev, &queue->rsps[i]); - kfree(queue->rsps); + kvfree(queue->rsps); sbitmap_free(&queue->rsp_tags); } diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index d543da09ef8e..15416ff0eac4 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -1484,7 +1484,7 @@ static int nvmet_tcp_alloc_cmds(struct nvmet_tcp_queue *queue) struct nvmet_tcp_cmd *cmds; int i, ret = -EINVAL, nr_cmds = queue->nr_cmds; - cmds = kcalloc(nr_cmds, sizeof(struct nvmet_tcp_cmd), GFP_KERNEL); + cmds = kvcalloc(nr_cmds, sizeof(struct nvmet_tcp_cmd), GFP_KERNEL); if (!cmds) goto out; @@ -1500,7 +1500,7 @@ static int nvmet_tcp_alloc_cmds(struct nvmet_tcp_queue *queue) out_free: while (--i >= 0) nvmet_tcp_free_cmd(cmds + i); - kfree(cmds); + kvfree(cmds); out: return ret; } @@ -1514,7 +1514,7 @@ static void nvmet_tcp_free_cmds(struct nvmet_tcp_queue *queue) nvmet_tcp_free_cmd(cmds + i); nvmet_tcp_free_cmd(&queue->connect); - kfree(cmds); + kvfree(cmds); } static void nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue) diff --git a/drivers/of/property.c b/drivers/of/property.c index c1feb631e383..4e3524227720 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -148,6 +148,39 @@ static void *of_find_property_value_of_size(const struct device_node *np, } /** + * of_property_read_u8_index - Find and read a u8 from a multi-value property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the u8 in the list of values + * @out_value: pointer to return value, modified only if no error. + * + * Search for a property in a device node and read nth 8-bit value from + * it. + * + * Return: 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid u8 value can be decoded. + */ +int of_property_read_u8_index(const struct device_node *np, + const char *propname, + u32 index, u8 *out_value) +{ + const u8 *val = of_find_property_value_of_size(np, propname, + ((index + 1) * sizeof(*out_value)), + 0, NULL); + + if (IS_ERR(val)) + return PTR_ERR(val); + + *out_value = val[index]; + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u8_index); + +/** * of_property_read_u16_index - Find and read a u16 from a multi-value property. * * @np: device node from which the property value is to be read. diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c index 667e6d629474..83ec66a70823 100644 --- a/drivers/pci/controller/pcie-rzg3s-host.c +++ b/drivers/pci/controller/pcie-rzg3s-host.c @@ -479,7 +479,7 @@ static void rzg3s_pcie_intx_irq_handler(struct irq_desc *desc) static irqreturn_t rzg3s_pcie_msi_irq(int irq, void *data) { u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG; - DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR); + DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR) = {0}; struct rzg3s_pcie_host *host = data; struct rzg3s_pcie_msi *msi = &host->msi; unsigned long bit; diff --git a/drivers/phy/broadcom/phy-bcm63xx-usbh.c b/drivers/phy/broadcom/phy-bcm63xx-usbh.c index 647644de041b..29fd6791bae6 100644 --- a/drivers/phy/broadcom/phy-bcm63xx-usbh.c +++ b/drivers/phy/broadcom/phy-bcm63xx-usbh.c @@ -375,7 +375,7 @@ static struct phy *bcm63xx_usbh_phy_xlate(struct device *dev, return of_phy_simple_xlate(dev, args); } -static int __init bcm63xx_usbh_phy_probe(struct platform_device *pdev) +static int bcm63xx_usbh_phy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct bcm63xx_usbh_phy *usbh; @@ -432,7 +432,7 @@ static int __init bcm63xx_usbh_phy_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id bcm63xx_usbh_phy_ids[] __initconst = { +static const struct of_device_id bcm63xx_usbh_phy_ids[] = { { .compatible = "brcm,bcm6318-usbh-phy", .data = &usbh_bcm6318 }, { .compatible = "brcm,bcm6328-usbh-phy", .data = &usbh_bcm6328 }, { .compatible = "brcm,bcm6358-usbh-phy", .data = &usbh_bcm6358 }, @@ -443,7 +443,7 @@ static const struct of_device_id bcm63xx_usbh_phy_ids[] __initconst = { }; MODULE_DEVICE_TABLE(of, bcm63xx_usbh_phy_ids); -static struct platform_driver bcm63xx_usbh_phy_driver __refdata = { +static struct platform_driver bcm63xx_usbh_phy_driver = { .driver = { .name = "bcm63xx-usbh-phy", .of_match_table = bcm63xx_usbh_phy_ids, diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index b94f242420fc..ad8a55012e42 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c @@ -16,6 +16,7 @@ #define PHY_CTRL0_REF_SSP_EN BIT(2) #define PHY_CTRL0_FSEL_MASK GENMASK(10, 5) #define PHY_CTRL0_FSEL_24M 0x2a +#define PHY_CTRL0_FSEL_100M 0x27 #define PHY_CTRL1 0x4 #define PHY_CTRL1_RESET BIT(0) @@ -108,6 +109,7 @@ struct tca_blk { struct imx8mq_usb_phy { struct phy *phy; struct clk *clk; + struct clk *alt_clk; void __iomem *base; struct regulator *vbus; struct tca_blk *tca; @@ -582,7 +584,8 @@ static int imx8mp_usb_phy_init(struct phy *phy) /* USB3.0 PHY signal fsel for 24M ref */ value = readl(imx_phy->base + PHY_CTRL0); value &= ~PHY_CTRL0_FSEL_MASK; - value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M); + value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, imx_phy->alt_clk ? + PHY_CTRL0_FSEL_100M : PHY_CTRL0_FSEL_24M); writel(value, imx_phy->base + PHY_CTRL0); /* Disable alt_clk_en and use internal MPLL clocks */ @@ -626,13 +629,24 @@ static int imx8mq_phy_power_on(struct phy *phy) if (ret) return ret; - return clk_prepare_enable(imx_phy->clk); + ret = clk_prepare_enable(imx_phy->clk); + if (ret) + return ret; + + ret = clk_prepare_enable(imx_phy->alt_clk); + if (ret) { + clk_disable_unprepare(imx_phy->clk); + return ret; + } + + return ret; } static int imx8mq_phy_power_off(struct phy *phy) { struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); + clk_disable_unprepare(imx_phy->alt_clk); clk_disable_unprepare(imx_phy->clk); regulator_disable(imx_phy->vbus); @@ -681,6 +695,11 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(imx_phy->clk); } + imx_phy->alt_clk = devm_clk_get_optional(dev, "alt"); + if (IS_ERR(imx_phy->alt_clk)) + return dev_err_probe(dev, PTR_ERR(imx_phy->alt_clk), + "Failed to get alt clk\n"); + imx_phy->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(imx_phy->base)) return PTR_ERR(imx_phy->base); diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c index 5dca93cd325c..977d21d753a5 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c @@ -533,7 +533,7 @@ static struct phy *imx_hsio_xlate(struct device *dev, static int imx_hsio_probe(struct platform_device *pdev) { - int i; + int i, ret; void __iomem *off; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -545,6 +545,9 @@ static int imx_hsio_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = &pdev->dev; priv->drvdata = of_device_get_match_data(dev); + ret = devm_mutex_init(dev, &priv->lock); + if (ret) + return ret; /* Get HSIO configuration mode */ if (of_property_read_string(np, "fsl,hsio-cfg", &priv->hsio_cfg)) diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index f59caff4b3d4..330356706ad7 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -17,32 +17,41 @@ struct can_transceiver_data { u32 flags; #define CAN_TRANSCEIVER_STB_PRESENT BIT(0) #define CAN_TRANSCEIVER_EN_PRESENT BIT(1) +#define CAN_TRANSCEIVER_DUAL_CH BIT(2) +#define CAN_TRANSCEIVER_SILENT_PRESENT BIT(3) }; struct can_transceiver_phy { struct phy *generic_phy; + struct gpio_desc *silent_gpio; struct gpio_desc *standby_gpio; struct gpio_desc *enable_gpio; + struct can_transceiver_priv *priv; +}; + +struct can_transceiver_priv { struct mux_state *mux_state; + int num_ch; + struct can_transceiver_phy can_transceiver_phy[] __counted_by(num_ch); }; /* Power on function */ static int can_transceiver_phy_power_on(struct phy *phy) { struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy); + struct can_transceiver_priv *priv = can_transceiver_phy->priv; int ret; - if (can_transceiver_phy->mux_state) { - ret = mux_state_select(can_transceiver_phy->mux_state); + if (priv->mux_state) { + ret = mux_state_select(priv->mux_state); if (ret) { dev_err(&phy->dev, "Failed to select CAN mux: %d\n", ret); return ret; } } - if (can_transceiver_phy->standby_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0); - if (can_transceiver_phy->enable_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 1); + gpiod_set_value_cansleep(can_transceiver_phy->silent_gpio, 0); + gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0); + gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 1); return 0; } @@ -51,13 +60,13 @@ static int can_transceiver_phy_power_on(struct phy *phy) static int can_transceiver_phy_power_off(struct phy *phy) { struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy); + struct can_transceiver_priv *priv = can_transceiver_phy->priv; - if (can_transceiver_phy->standby_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1); - if (can_transceiver_phy->enable_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0); - if (can_transceiver_phy->mux_state) - mux_state_deselect(can_transceiver_phy->mux_state); + gpiod_set_value_cansleep(can_transceiver_phy->silent_gpio, 1); + gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1); + gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0); + if (priv->mux_state) + mux_state_deselect(priv->mux_state); return 0; } @@ -76,6 +85,18 @@ static const struct can_transceiver_data tcan1043_drvdata = { .flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_EN_PRESENT, }; +static const struct can_transceiver_data tja1048_drvdata = { + .flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_DUAL_CH, +}; + +static const struct can_transceiver_data tja1051_drvdata = { + .flags = CAN_TRANSCEIVER_SILENT_PRESENT | CAN_TRANSCEIVER_EN_PRESENT, +}; + +static const struct can_transceiver_data tja1057_drvdata = { + .flags = CAN_TRANSCEIVER_SILENT_PRESENT, +}; + static const struct of_device_id can_transceiver_phy_ids[] = { { .compatible = "ti,tcan1042", @@ -86,6 +107,18 @@ static const struct of_device_id can_transceiver_phy_ids[] = { .data = &tcan1043_drvdata }, { + .compatible = "nxp,tja1048", + .data = &tja1048_drvdata + }, + { + .compatible = "nxp,tja1051", + .data = &tja1051_drvdata + }, + { + .compatible = "nxp,tja1057", + .data = &tja1057_drvdata + }, + { .compatible = "nxp,tjr1443", .data = &tcan1043_drvdata }, @@ -103,64 +136,107 @@ devm_mux_state_get_optional(struct device *dev, const char *mux_name) return devm_mux_state_get(dev, mux_name); } +static struct phy *can_transceiver_phy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct can_transceiver_priv *priv = dev_get_drvdata(dev); + u32 idx; + + if (priv->num_ch == 1) + return priv->can_transceiver_phy[0].generic_phy; + + if (args->args_count != 1) + return ERR_PTR(-EINVAL); + + idx = args->args[0]; + if (idx >= priv->num_ch) + return ERR_PTR(-EINVAL); + + return priv->can_transceiver_phy[idx].generic_phy; +} + static int can_transceiver_phy_probe(struct platform_device *pdev) { struct phy_provider *phy_provider; struct device *dev = &pdev->dev; struct can_transceiver_phy *can_transceiver_phy; + struct can_transceiver_priv *priv; const struct can_transceiver_data *drvdata; const struct of_device_id *match; struct phy *phy; + struct gpio_desc *silent_gpio; struct gpio_desc *standby_gpio; struct gpio_desc *enable_gpio; struct mux_state *mux_state; u32 max_bitrate = 0; - int err; - - can_transceiver_phy = devm_kzalloc(dev, sizeof(struct can_transceiver_phy), GFP_KERNEL); - if (!can_transceiver_phy) - return -ENOMEM; + int err, i, num_ch = 1; match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node); drvdata = match->data; + if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH) + num_ch = 2; + + priv = devm_kzalloc(dev, struct_size(priv, can_transceiver_phy, num_ch), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->num_ch = num_ch; + platform_set_drvdata(pdev, priv); mux_state = devm_mux_state_get_optional(dev, NULL); if (IS_ERR(mux_state)) return PTR_ERR(mux_state); - can_transceiver_phy->mux_state = mux_state; - - phy = devm_phy_create(dev, dev->of_node, - &can_transceiver_phy_ops); - if (IS_ERR(phy)) { - dev_err(dev, "failed to create can transceiver phy\n"); - return PTR_ERR(phy); - } + priv->mux_state = mux_state; err = device_property_read_u32(dev, "max-bitrate", &max_bitrate); if ((err != -EINVAL) && !max_bitrate) dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n"); - phy->attrs.max_link_rate = max_bitrate; - can_transceiver_phy->generic_phy = phy; + for (i = 0; i < num_ch; i++) { + can_transceiver_phy = &priv->can_transceiver_phy[i]; + can_transceiver_phy->priv = priv; - if (drvdata->flags & CAN_TRANSCEIVER_STB_PRESENT) { - standby_gpio = devm_gpiod_get_optional(dev, "standby", GPIOD_OUT_HIGH); - if (IS_ERR(standby_gpio)) - return PTR_ERR(standby_gpio); - can_transceiver_phy->standby_gpio = standby_gpio; - } + phy = devm_phy_create(dev, dev->of_node, &can_transceiver_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create can transceiver phy\n"); + return PTR_ERR(phy); + } - if (drvdata->flags & CAN_TRANSCEIVER_EN_PRESENT) { - enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(enable_gpio)) - return PTR_ERR(enable_gpio); - can_transceiver_phy->enable_gpio = enable_gpio; - } + phy->attrs.max_link_rate = max_bitrate; + + can_transceiver_phy->generic_phy = phy; + can_transceiver_phy->priv = priv; + + if (drvdata->flags & CAN_TRANSCEIVER_STB_PRESENT) { + standby_gpio = devm_gpiod_get_index_optional(dev, "standby", i, + GPIOD_OUT_HIGH); + if (IS_ERR(standby_gpio)) + return PTR_ERR(standby_gpio); + can_transceiver_phy->standby_gpio = standby_gpio; + } + + if (drvdata->flags & CAN_TRANSCEIVER_EN_PRESENT) { + enable_gpio = devm_gpiod_get_index_optional(dev, "enable", i, + GPIOD_OUT_LOW); + if (IS_ERR(enable_gpio)) + return PTR_ERR(enable_gpio); + can_transceiver_phy->enable_gpio = enable_gpio; + } + + if (drvdata->flags & CAN_TRANSCEIVER_SILENT_PRESENT) { + silent_gpio = devm_gpiod_get_index_optional(dev, "silent", i, + GPIOD_OUT_LOW); + if (IS_ERR(silent_gpio)) + return PTR_ERR(silent_gpio); + can_transceiver_phy->silent_gpio = silent_gpio; + } - phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy); + phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy); + + } - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + phy_provider = devm_of_phy_provider_register(dev, can_transceiver_phy_xlate); return PTR_ERR_OR_ZERO(phy_provider); } diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 04a5a34e7a95..8d227890a345 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -361,7 +361,7 @@ int phy_power_off(struct phy *phy) mutex_lock(&phy->mutex); if (phy->power_count == 1 && phy->ops->power_off) { - ret = phy->ops->power_off(phy); + ret = phy->ops->power_off(phy); if (ret < 0) { dev_err(&phy->dev, "phy poweroff failed --> %d\n", ret); mutex_unlock(&phy->mutex); @@ -521,6 +521,31 @@ int phy_notify_disconnect(struct phy *phy, int port) EXPORT_SYMBOL_GPL(phy_notify_disconnect); /** + * phy_notify_state() - phy state notification + * @phy: the PHY returned by phy_get() + * @state: the PHY state + * + * Notify the PHY of a state transition. Used to notify and + * configure the PHY accordingly. + * + * Returns: %0 if successful, a negative error code otherwise + */ +int phy_notify_state(struct phy *phy, union phy_notify state) +{ + int ret; + + if (!phy || !phy->ops->notify_phystate) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->notify_phystate(phy, state); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_notify_state); + +/** * phy_configure() - Changes the phy parameters * @phy: the phy returned by phy_get() * @opts: New configuration to apply diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c index 0a0d2d9fc846..95cd3175926d 100644 --- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c @@ -25,6 +25,7 @@ #define POR BIT(1) #define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) +#define PHY_ENABLE BIT(0) #define SIDDQ_SEL BIT(1) #define SIDDQ BIT(2) #define FSEL GENMASK(6, 4) @@ -81,6 +82,7 @@ struct m31_eusb2_priv_data { static const struct m31_phy_tbl_entry m31_eusb2_setup_tbl[] = { M31_EUSB_PHY_INIT_CFG(USB_PHY_CFG0, UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 1), M31_EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL5, POR, 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL_COMMON0, PHY_ENABLE, 1), M31_EUSB_PHY_INIT_CFG(USB_PHY_CFG1, PLL_EN, 1), M31_EUSB_PHY_INIT_CFG(USB_PHY_FSEL_SEL, FSEL_SEL, 1), }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 7b5af30f1d02..9e2a6c5d0f58 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_graph.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -1643,14 +1644,9 @@ static const struct qmp_phy_init_tbl x1e80100_usb43dp_pcs_usb_tbl[] = { }; /* list of regulators */ -struct qmp_regulator_data { - const char *name; - unsigned int enable_load; -}; - -static struct qmp_regulator_data qmp_phy_vreg_l[] = { - { .name = "vdda-phy", .enable_load = 21800 }, - { .name = "vdda-pll", .enable_load = 36000 }, +static struct regulator_bulk_data qmp_phy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 21800, }, + { .supply = "vdda-pll", .init_load_uA = 36000, }, }; static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = { @@ -1744,6 +1740,26 @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = { { 0x22, 0xff, 0xff, 0xff } }; +struct qmp_combo_lane_mapping { + unsigned int lanes_count; + enum typec_orientation orientation; + u32 lanes[4]; +}; + +static const struct qmp_combo_lane_mapping usb3_data_lanes[] = { + { 2, TYPEC_ORIENTATION_NORMAL, { 1, 0 }}, + { 2, TYPEC_ORIENTATION_REVERSE, { 2, 3 }}, +}; + +static const struct qmp_combo_lane_mapping dp_data_lanes[] = { + { 1, TYPEC_ORIENTATION_NORMAL, { 3 }}, + { 1, TYPEC_ORIENTATION_REVERSE, { 0 }}, + { 2, TYPEC_ORIENTATION_NORMAL, { 3, 2 }}, + { 2, TYPEC_ORIENTATION_REVERSE, { 0, 1 }}, + { 4, TYPEC_ORIENTATION_NORMAL, { 3, 2, 1, 0 }}, + { 4, TYPEC_ORIENTATION_REVERSE, { 0, 1, 2, 3 }}, +}; + struct qmp_combo; struct qmp_combo_offsets { @@ -1808,7 +1824,7 @@ struct qmp_phy_cfg { const char * const *reset_list; int num_resets; /* regulators to be requested */ - const struct qmp_regulator_data *vreg_list; + const struct regulator_bulk_data *vreg_list; int num_vregs; /* array of registers with different offsets */ @@ -3439,39 +3455,6 @@ static const struct dev_pm_ops qmp_combo_pm_ops = { qmp_combo_runtime_resume, NULL) }; -static int qmp_combo_vreg_init(struct qmp_combo *qmp) -{ - const struct qmp_phy_cfg *cfg = qmp->cfg; - struct device *dev = qmp->dev; - int num = cfg->num_vregs; - int ret, i; - - qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); - if (!qmp->vregs) - return -ENOMEM; - - for (i = 0; i < num; i++) - qmp->vregs[i].supply = cfg->vreg_list[i].name; - - ret = devm_regulator_bulk_get(dev, num, qmp->vregs); - if (ret) { - dev_err(dev, "failed at devm_regulator_bulk_get\n"); - return ret; - } - - for (i = 0; i < num; i++) { - ret = regulator_set_load(qmp->vregs[i].consumer, - cfg->vreg_list[i].enable_load); - if (ret) { - dev_err(dev, "failed to set load at %s\n", - qmp->vregs[i].supply); - return ret; - } - } - - return 0; -} - static int qmp_combo_reset_init(struct qmp_combo *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -4117,6 +4100,84 @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phand return ERR_PTR(-EINVAL); } +static void qmp_combo_find_lanes_orientation(const struct qmp_combo_lane_mapping *mapping, + unsigned int mapping_count, + u32 *lanes, unsigned int lanes_count, + enum typec_orientation *orientation) +{ + int i; + + for (i = 0; i < mapping_count; i++) { + if (mapping[i].lanes_count != lanes_count) + continue; + if (!memcmp(mapping[i].lanes, lanes, sizeof(u32) * lanes_count)) { + *orientation = mapping[i].orientation; + return; + } + } +} + +static int qmp_combo_get_dt_lanes_mapping(struct device *dev, unsigned int endpoint, + u32 *data_lanes, unsigned int max, + unsigned int *count) +{ + struct device_node *ep __free(device_node) = NULL; + int ret; + + ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, endpoint); + if (!ep) + return -EINVAL; + + ret = of_property_count_u32_elems(ep, "data-lanes"); + if (ret < 0) + return ret; + + *count = ret; + if (*count > max) + return -EINVAL; + + return of_property_read_u32_array(ep, "data-lanes", data_lanes, + min_t(unsigned int, *count, max)); +} + +static int qmp_combo_get_dt_dp_orientation(struct device *dev, + enum typec_orientation *orientation) +{ + unsigned int count; + u32 data_lanes[4]; + int ret; + + /* DP is described on the first endpoint of the first port */ + ret = qmp_combo_get_dt_lanes_mapping(dev, 0, data_lanes, 4, &count); + if (ret < 0) + return ret == -EINVAL ? 0 : ret; + + /* Search for a match and only update orientation if found */ + qmp_combo_find_lanes_orientation(dp_data_lanes, ARRAY_SIZE(dp_data_lanes), + data_lanes, count, orientation); + + return 0; +} + +static int qmp_combo_get_dt_usb3_orientation(struct device *dev, + enum typec_orientation *orientation) +{ + unsigned int count; + u32 data_lanes[2]; + int ret; + + /* USB3 is described on the second endpoint of the first port */ + ret = qmp_combo_get_dt_lanes_mapping(dev, 1, data_lanes, 2, &count); + if (ret < 0) + return ret == -EINVAL ? 0 : ret; + + /* Search for a match and only update orientation if found */ + qmp_combo_find_lanes_orientation(usb3_data_lanes, ARRAY_SIZE(usb3_data_lanes), + data_lanes, count, orientation); + + return 0; +} + static int qmp_combo_probe(struct platform_device *pdev) { struct qmp_combo *qmp; @@ -4144,7 +4205,8 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) return ret; - ret = qmp_combo_vreg_init(qmp); + ret = devm_regulator_bulk_get_const(dev, qmp->cfg->num_vregs, + qmp->cfg->vreg_list, &qmp->vregs); if (ret) return ret; @@ -4167,9 +4229,41 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - ret = qmp_combo_typec_register(qmp); - if (ret) - goto err_node_put; + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + + if (of_property_present(dev->of_node, "mode-switch") || + of_property_present(dev->of_node, "orientation-switch")) { + ret = qmp_combo_typec_register(qmp); + if (ret) + goto err_node_put; + } else { + enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE; + enum typec_orientation usb3_orientation = TYPEC_ORIENTATION_NONE; + + ret = qmp_combo_get_dt_dp_orientation(dev, &dp_orientation); + if (ret) + goto err_node_put; + + ret = qmp_combo_get_dt_usb3_orientation(dev, &usb3_orientation); + if (ret) + goto err_node_put; + + if (dp_orientation == TYPEC_ORIENTATION_NONE && + usb3_orientation != TYPEC_ORIENTATION_NONE) { + qmp->qmpphy_mode = QMPPHY_MODE_USB3_ONLY; + qmp->orientation = usb3_orientation; + } else if (usb3_orientation == TYPEC_ORIENTATION_NONE && + dp_orientation != TYPEC_ORIENTATION_NONE) { + qmp->qmpphy_mode = QMPPHY_MODE_DP_ONLY; + qmp->orientation = dp_orientation; + } else if (dp_orientation != TYPEC_ORIENTATION_NONE && + dp_orientation == usb3_orientation) { + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + qmp->orientation = dp_orientation; + } else { + dev_warn(dev, "unable to determine orientation & mode from data-lanes"); + } + } ret = drm_aux_bridge_register(dev); if (ret) @@ -4189,11 +4283,6 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - /* - * The hw default is USB3_ONLY, but USB3+DP mode lets us more easily - * check both sub-blocks' init tables for blunders at probe time. - */ - qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops); if (IS_ERR(qmp->usb_phy)) { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 62b1c845b627..86b1b7e2da86 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -100,6 +100,12 @@ static const unsigned int pciephy_v7_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_POWER_DOWN_CONTROL, }; +static const unsigned int pciephy_v8_50_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V8_50_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V8_50_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V8_50_PCS_POWER_DOWN_CONTROL, +}; + static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14), QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), @@ -3072,6 +3078,7 @@ struct qmp_pcie_offsets { u16 rx2; u16 txz; u16 rxz; + u16 txrxz; u16 ln_shrd; }; @@ -3356,6 +3363,12 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_30 = { .ln_shrd = 0x8000, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v8_50 = { + .serdes = 0x8000, + .pcs = 0x9000, + .txrxz = 0xd000, +}; + static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { .lanes = 1, @@ -4412,6 +4425,22 @@ static const struct qmp_phy_cfg qmp_v6_gen4x4_pciephy_cfg = { .phy_status = PHYSTATUS_4_20, }; +static const struct qmp_phy_cfg glymur_qmp_gen5x4_pciephy_cfg = { + .lanes = 4, + + .offsets = &qmp_pcie_offsets_v8_50, + + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + + .regs = pciephy_v8_50_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -5163,6 +5192,9 @@ err_node_put: static const struct of_device_id qmp_pcie_of_match_table[] = { { + .compatible = "qcom,glymur-qmp-gen5x4-pcie-phy", + .data = &glymur_qmp_gen5x4_pciephy_cfg, + }, { .compatible = "qcom,ipq6018-qmp-pcie-phy", .data = &ipq6018_pciephy_cfg, }, { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h new file mode 100644 index 000000000000..325c127e8eb7 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8_50.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef QCOM_PHY_QMP_PCS_V8_50_H_ +#define QCOM_PHY_QMP_PCS_V8_50_H_ + +#define QPHY_V8_50_PCS_STATUS1 0x010 +#define QPHY_V8_50_PCS_START_CONTROL 0x05c +#define QPHY_V8_50_PCS_POWER_DOWN_CONTROL 0x64 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index f58c82b2dd23..da2a7ad2cdcc 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -58,6 +58,8 @@ #include "phy-qcom-qmp-pcs-v8.h" +#include "phy-qcom-qmp-pcs-v8_50.h" + /* QPHY_SW_RESET bit */ #define SW_RESET BIT(0) /* QPHY_POWER_DOWN_CONTROL */ diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig index e342eef0640b..16211072098e 100644 --- a/drivers/phy/renesas/Kconfig +++ b/drivers/phy/renesas/Kconfig @@ -40,3 +40,10 @@ config PHY_RCAR_GEN3_USB3 select GENERIC_PHY help Support for USB 3.0 PHY found on Renesas R-Car generation 3 SoCs. + +config PHY_RZ_G3E_USB3 + tristate "Renesas RZ/G3E USB 3.0 PHY driver" + depends on ARCH_RENESAS || COMPILE_TEST + select GENERIC_PHY + help + Support for USB 3.0 PHY found on Renesas RZ/G3E SoCs. diff --git a/drivers/phy/renesas/Makefile b/drivers/phy/renesas/Makefile index 8896d1919faa..0e98083f2f0c 100644 --- a/drivers/phy/renesas/Makefile +++ b/drivers/phy/renesas/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o +obj-$(CONFIG_PHY_RZ_G3E_USB3) += phy-rzg3e-usb3.o diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c index feca4cb2ff4d..c0e5a4ac82de 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-pcie.c +++ b/drivers/phy/renesas/phy-rcar-gen3-pcie.c @@ -128,7 +128,7 @@ error: static void rcar_gen3_phy_pcie_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); -}; +} static struct platform_driver rcar_gen3_phy_driver = { .driver = { diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 3f6b480e1092..582de10d5beb 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -132,9 +132,9 @@ struct rcar_gen3_chan { struct device *dev; /* platform_device's device */ const struct rcar_gen3_phy_drv_data *phy_data; struct extcon_dev *extcon; + struct reset_control *rstc; struct rcar_gen3_phy rphys[NUM_OF_PHYS]; struct regulator *vbus; - struct reset_control *rstc; struct work_struct work; spinlock_t lock; /* protects access to hardware and driver data structure. */ enum usb_dr_mode dr_mode; @@ -771,33 +771,32 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) return candidate; } +static void rcar_gen3_reset_assert(void *data) +{ + reset_control_assert(data); +} + static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) { struct device *dev = channel->dev; int ret; u32 val; - channel->rstc = devm_reset_control_array_get_shared(dev); - if (IS_ERR(channel->rstc)) - return PTR_ERR(channel->rstc); + if (!channel->phy_data->init_bus) + return 0; ret = pm_runtime_resume_and_get(dev); if (ret) return ret; - ret = reset_control_deassert(channel->rstc); - if (ret) - goto rpm_put; - val = readl(channel->base + USB2_AHB_BUS_CTR); val &= ~USB2_AHB_BUS_CTR_MBL_MASK; val |= USB2_AHB_BUS_CTR_MBL_INCR4; writel(val, channel->base + USB2_AHB_BUS_CTR); -rpm_put: pm_runtime_put(dev); - return ret; + return 0; } static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) @@ -837,6 +836,18 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) } } + channel->rstc = devm_reset_control_array_get_optional_shared(dev); + if (IS_ERR(channel->rstc)) + return PTR_ERR(channel->rstc); + + ret = reset_control_deassert(channel->rstc); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, rcar_gen3_reset_assert, channel->rstc); + if (ret) + return ret; + /* * devm_phy_create() will call pm_runtime_enable(&phy->dev); * And then, phy-core will manage runtime pm for this device. @@ -852,11 +863,9 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, channel); channel->dev = dev; - if (channel->phy_data->init_bus) { - ret = rcar_gen3_phy_usb2_init_bus(channel); - if (ret) - goto error; - } + ret = rcar_gen3_phy_usb2_init_bus(channel); + if (ret) + goto error; spin_lock_init(&channel->lock); for (i = 0; i < NUM_OF_PHYS; i++) { @@ -924,14 +933,41 @@ static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev) if (channel->is_otg_channel) device_remove_file(&pdev->dev, &dev_attr_role); - reset_control_assert(channel->rstc); pm_runtime_disable(&pdev->dev); -}; +} + +static int rcar_gen3_phy_usb2_suspend(struct device *dev) +{ + struct rcar_gen3_chan *channel = dev_get_drvdata(dev); + + return reset_control_assert(channel->rstc); +} + +static int rcar_gen3_phy_usb2_resume(struct device *dev) +{ + struct rcar_gen3_chan *channel = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(channel->rstc); + if (ret) + return ret; + + ret = rcar_gen3_phy_usb2_init_bus(channel); + if (ret) + reset_control_assert(channel->rstc); + + return ret; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(rcar_gen3_phy_usb2_pm_ops, + rcar_gen3_phy_usb2_suspend, + rcar_gen3_phy_usb2_resume); static struct platform_driver rcar_gen3_phy_usb2_driver = { .driver = { .name = "phy_rcar_gen3_usb2", .of_match_table = rcar_gen3_phy_usb2_match_table, + .pm = pm_ptr(&rcar_gen3_phy_usb2_pm_ops), }, .probe = rcar_gen3_phy_usb2_probe, .remove = rcar_gen3_phy_usb2_remove, diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c index 5c267d148c90..0420f5b283ce 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c @@ -202,7 +202,7 @@ error: static void rcar_gen3_phy_usb3_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); -}; +} static struct platform_driver rcar_gen3_phy_usb3_driver = { .driver = { diff --git a/drivers/phy/renesas/phy-rzg3e-usb3.c b/drivers/phy/renesas/phy-rzg3e-usb3.c new file mode 100644 index 000000000000..6b3453ea0004 --- /dev/null +++ b/drivers/phy/renesas/phy-rzg3e-usb3.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G3E USB3.0 PHY driver + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#define USB3_TEST_RESET 0x0000 +#define USB3_TEST_UTMICTRL2 0x0b04 +#define USB3_TEST_PRMCTRL5_R 0x0c10 +#define USB3_TEST_PRMCTRL6_R 0x0c14 + +#define USB3_TEST_RSTCTRL 0x1000 +#define USB3_TEST_CLKCTRL 0x1004 +#define USB3_TEST_RAMCTRL 0x100c +#define USB3_TEST_CREGCTRL 0x1010 +#define USB3_TEST_LANECONFIG0 0x1030 + +#define USB3_TEST_RESET_PORTRESET0_CTRL BIT(9) +#define USB3_TEST_RESET_SIDDQ BIT(3) +#define USB3_TEST_RESET_PHY_RESET BIT(2) +#define USB3_TEST_RESET_PORTRESET0 BIT(1) +#define USB3_TEST_RESET_RELEASE_OVERRIDE (0) + +#define USB3_TEST_UTMICTRL2_CTRL_MASK GENMASK(9, 8) +#define USB3_TEST_UTMICTRL2_MODE_MASK GENMASK(1, 0) + +#define USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK GENMASK(2, 1) + +#define USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK GENMASK(2, 0) + +#define USB3_TEST_RSTCTRL_HARDRESET_ODEN BIT(9) +#define USB3_TEST_RSTCTRL_PIPERESET_ODEN BIT(8) +#define USB3_TEST_RSTCTRL_HARDRESET BIT(1) +#define USB3_TEST_RSTCTRL_PIPERESET BIT(0) +#define USB3_TEST_RSTCTRL_ASSERT \ + (USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN | \ + USB3_TEST_RSTCTRL_HARDRESET | USB3_TEST_RSTCTRL_PIPERESET) +#define USB3_TEST_RSTCTRL_RELEASE_HARDRESET \ + (USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN | \ + USB3_TEST_RSTCTRL_PIPERESET) +#define USB3_TEST_RSTCTRL_DEASSERT \ + (USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN) +#define USB3_TEST_RSTCTRL_RELEASE_OVERRIDE (0) + +#define USB3_TEST_CLKCTRL_MPLLA_SSC_EN BIT(2) + +#define USB3_TEST_RAMCTRL_SRAM_INIT_DONE BIT(2) +#define USB3_TEST_RAMCTRL_SRAM_EXT_LD_DONE BIT(0) + +#define USB3_TEST_CREGCTRL_PARA_SEL BIT(8) + +#define USB3_TEST_LANECONFIG0_DEFAULT (0xd) + +struct rz_usb3 { + void __iomem *base; + struct reset_control *rstc; + bool skip_reinit; +}; + +static void rzg3e_phy_usb2test_phy_init(void __iomem *base) +{ + u32 val; + + val = readl(base + USB3_TEST_UTMICTRL2); + val |= USB3_TEST_UTMICTRL2_CTRL_MASK | USB3_TEST_UTMICTRL2_MODE_MASK; + writel(val, base + USB3_TEST_UTMICTRL2); + + val = readl(base + USB3_TEST_PRMCTRL5_R); + val &= ~USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK; + val |= FIELD_PREP(USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK, 2); + writel(val, base + USB3_TEST_PRMCTRL5_R); + + val = readl(base + USB3_TEST_PRMCTRL6_R); + val &= ~USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK; + val |= FIELD_PREP(USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK, 7); + writel(val, base + USB3_TEST_PRMCTRL6_R); + + val = readl(base + USB3_TEST_RESET); + val &= ~USB3_TEST_RESET_SIDDQ; + val |= USB3_TEST_RESET_PORTRESET0_CTRL | USB3_TEST_RESET_PHY_RESET | + USB3_TEST_RESET_PORTRESET0; + writel(val, base + USB3_TEST_RESET); + fsleep(10); + + val &= ~(USB3_TEST_RESET_PHY_RESET | USB3_TEST_RESET_PORTRESET0); + writel(val, base + USB3_TEST_RESET); + fsleep(10); + + val = readl(base + USB3_TEST_UTMICTRL2); + val &= ~USB3_TEST_UTMICTRL2_CTRL_MASK; + writel(val, base + USB3_TEST_UTMICTRL2); + + writel(USB3_TEST_RESET_RELEASE_OVERRIDE, base + USB3_TEST_RESET); +} + +static int rzg3e_phy_usb3test_phy_init(void __iomem *base) +{ + int ret; + u32 val; + + writel(USB3_TEST_CREGCTRL_PARA_SEL, base + USB3_TEST_CREGCTRL); + writel(USB3_TEST_RSTCTRL_ASSERT, base + USB3_TEST_RSTCTRL); + fsleep(20); + + writel(USB3_TEST_CLKCTRL_MPLLA_SSC_EN, base + USB3_TEST_CLKCTRL); + writel(USB3_TEST_LANECONFIG0_DEFAULT, base + USB3_TEST_LANECONFIG0); + writel(USB3_TEST_RSTCTRL_RELEASE_HARDRESET, base + USB3_TEST_RSTCTRL); + + ret = readl_poll_timeout_atomic(base + USB3_TEST_RAMCTRL, val, + val & USB3_TEST_RAMCTRL_SRAM_INIT_DONE, 1, 10000); + if (ret) + return ret; + + writel(USB3_TEST_RSTCTRL_DEASSERT, base + USB3_TEST_RSTCTRL); + writel(USB3_TEST_RAMCTRL_SRAM_EXT_LD_DONE, base + USB3_TEST_RAMCTRL); + writel(USB3_TEST_RSTCTRL_RELEASE_OVERRIDE, base + USB3_TEST_RSTCTRL); + + return 0; +} + +static int rzg3e_phy_usb3_init_helper(void __iomem *base) +{ + rzg3e_phy_usb2test_phy_init(base); + + return rzg3e_phy_usb3test_phy_init(base); +} + +static int rzg3e_phy_usb3_init(struct phy *p) +{ + struct rz_usb3 *r = phy_get_drvdata(p); + int ret = 0; + + if (!r->skip_reinit) + ret = rzg3e_phy_usb3_init_helper(r->base); + + return ret; +} + +static const struct phy_ops rzg3e_phy_usb3_ops = { + .init = rzg3e_phy_usb3_init, + .owner = THIS_MODULE, +}; + +static int rzg3e_phy_usb3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct rz_usb3 *r; + struct phy *phy; + int ret; + + r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); + if (!r) + return -ENOMEM; + + r->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(r->base)) + return PTR_ERR(r->base); + + r->rstc = devm_reset_control_get_shared_deasserted(dev, NULL); + if (IS_ERR(r->rstc)) + return dev_err_probe(dev, PTR_ERR(r->rstc), "failed to get deasserted reset\n"); + + /* + * devm_phy_create() will call pm_runtime_enable(&phy->dev); + * And then, phy-core will manage runtime pm for this device. + */ + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + return ret; + + phy = devm_phy_create(dev, NULL, &rzg3e_phy_usb3_ops); + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), "failed to create USB3 PHY\n"); + + platform_set_drvdata(pdev, r); + phy_set_drvdata(phy, r); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) + return dev_err_probe(dev, PTR_ERR(provider), "failed to register PHY provider\n"); + + return 0; +} + +static int rzg3e_phy_usb3_suspend(struct device *dev) +{ + struct rz_usb3 *r = dev_get_drvdata(dev); + + pm_runtime_put(dev); + reset_control_assert(r->rstc); + r->skip_reinit = false; + + return 0; +} + +static int rzg3e_phy_usb3_resume(struct device *dev) +{ + struct rz_usb3 *r = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(r->rstc); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto reset_assert; + + ret = rzg3e_phy_usb3_init_helper(r->base); + if (ret) + goto pm_put; + + r->skip_reinit = true; + + return 0; + +pm_put: + pm_runtime_put(dev); +reset_assert: + reset_control_assert(r->rstc); + return ret; +} + +static const struct dev_pm_ops rzg3e_phy_usb3_pm = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(rzg3e_phy_usb3_suspend, rzg3e_phy_usb3_resume) +}; + +static const struct of_device_id rzg3e_phy_usb3_match_table[] = { + { .compatible = "renesas,r9a09g047-usb3-phy" }, + { /* Sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, rzg3e_phy_usb3_match_table); +static struct platform_driver rzg3e_phy_usb3_driver = { + .driver = { + .name = "phy_rzg3e_usb3", + .of_match_table = rzg3e_phy_usb3_match_table, + .pm = pm_sleep_ptr(&rzg3e_phy_usb3_pm), + }, + .probe = rzg3e_phy_usb3_probe, +}; +module_platform_driver(rzg3e_phy_usb3_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Renesas RZ/G3E USB3.0 PHY Driver"); +MODULE_AUTHOR("biju.das.jz@bp.renesas.com>"); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c index d5b1a4e2f7d3..30d5e5ddff4a 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c @@ -99,10 +99,30 @@ #define VOD_MID_RANGE 0x3 #define VOD_BIG_RANGE 0x7 #define VOD_MAX_RANGE 0xf +/* Analog Register Part: reg18 */ +#define LANE0_PRE_EMPHASIS_ENABLE_MASK BIT(6) +#define LANE0_PRE_EMPHASIS_ENABLE BIT(6) +#define LANE0_PRE_EMPHASIS_DISABLE 0 +#define LANE1_PRE_EMPHASIS_ENABLE_MASK BIT(5) +#define LANE1_PRE_EMPHASIS_ENABLE BIT(5) +#define LANE1_PRE_EMPHASIS_DISABLE 0 +/* Analog Register Part: reg19 */ +#define PRE_EMPHASIS_RANGE_SET_MASK GENMASK(7, 6) +#define PRE_EMPHASIS_RANGE_SET(x) UPDATE(x, 7, 6) /* Analog Register Part: reg1E */ #define PLL_MODE_SEL_MASK GENMASK(6, 5) #define PLL_MODE_SEL_LVDS_MODE 0 #define PLL_MODE_SEL_MIPI_MODE BIT(5) +/* Analog Register Part: reg20 */ +#define LANE0_PRE_EMPHASIS_RANGE_SET_MASK GENMASK(7, 6) +#define LANE0_PRE_EMPHASIS_RANGE_SET(x) UPDATE(x, 7, 6) +/* Analog Register Part: reg21 */ +#define LANE1_PRE_EMPHASIS_RANGE_SET_MASK GENMASK(7, 6) +#define LANE1_PRE_EMPHASIS_RANGE_SET(x) UPDATE(x, 7, 6) +#define PRE_EMPHASIS_MIN_RANGE 0x0 +#define PRE_EMPHASIS_MID_RANGE 0x1 +#define PRE_EMPHASIS_MAX_RANGE 0x2 +#define PRE_EMPHASIS_RESERVED_RANGE 0x3 /* Digital Register Part: reg00 */ #define REG_DIG_RSTN_MASK BIT(0) #define REG_DIG_RSTN_NORMAL BIT(0) @@ -193,6 +213,7 @@ enum phy_max_rate { MAX_1GHZ, + MAX_1_5GHZ, MAX_2_5GHZ, }; @@ -200,6 +221,7 @@ struct inno_video_phy_plat_data { const struct inno_mipi_dphy_timing *inno_mipi_dphy_timing_table; const unsigned int num_timings; enum phy_max_rate max_rate; + unsigned int max_lanes; }; struct inno_dsidphy { @@ -259,6 +281,24 @@ struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_1ghz[] = { }; static const +struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_1_5ghz[] = { + { 110, 0x02, 0x7f, 0x16, 0x02, 0x02}, + { 150, 0x02, 0x7f, 0x16, 0x03, 0x02}, + { 200, 0x02, 0x7f, 0x17, 0x04, 0x02}, + { 250, 0x02, 0x7f, 0x17, 0x05, 0x04}, + { 300, 0x02, 0x7f, 0x18, 0x06, 0x04}, + { 400, 0x03, 0x7e, 0x19, 0x07, 0x04}, + { 500, 0x03, 0x7c, 0x1b, 0x07, 0x08}, + { 600, 0x03, 0x70, 0x1d, 0x08, 0x10}, + { 700, 0x05, 0x40, 0x1e, 0x08, 0x30}, + { 800, 0x05, 0x02, 0x1f, 0x09, 0x30}, + {1000, 0x05, 0x08, 0x20, 0x09, 0x30}, + {1200, 0x06, 0x03, 0x32, 0x14, 0x0f}, + {1400, 0x09, 0x03, 0x32, 0x14, 0x0f}, + {1500, 0x0d, 0x42, 0x36, 0x0e, 0x0f}, +}; + +static const struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_2_5ghz[] = { { 110000000, 0x02, 0x7f, 0x16, 0x02, 0x02}, { 150000000, 0x02, 0x7f, 0x16, 0x03, 0x02}, @@ -372,6 +412,7 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) u32 hs_exit, clk_post, clk_pre, wakeup, lpx, ta_go, ta_sure, ta_wait; u32 hs_prepare, hs_trail, hs_zero, clk_lane_hs_zero, data_lane_hs_zero; unsigned int i; + u32 val; timings = inno->pdata->inno_mipi_dphy_timing_table; @@ -393,6 +434,23 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) phy_update_bits(inno, REGISTER_PART_ANALOG, 0x0b, CLOCK_LANE_VOD_RANGE_SET_MASK, CLOCK_LANE_VOD_RANGE_SET(VOD_MAX_RANGE)); + } else if (inno->pdata->max_rate == MAX_1_5GHZ) { + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x18, + LANE0_PRE_EMPHASIS_ENABLE_MASK, LANE0_PRE_EMPHASIS_ENABLE); + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x18, + LANE1_PRE_EMPHASIS_ENABLE_MASK, LANE1_PRE_EMPHASIS_ENABLE); + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x19, + PRE_EMPHASIS_RANGE_SET_MASK, + PRE_EMPHASIS_RANGE_SET(PRE_EMPHASIS_MID_RANGE)); + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x1a, + LANE0_PRE_EMPHASIS_RANGE_SET_MASK, + LANE0_PRE_EMPHASIS_RANGE_SET(PRE_EMPHASIS_MID_RANGE)); + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x1b, + LANE1_PRE_EMPHASIS_RANGE_SET_MASK, + LANE1_PRE_EMPHASIS_RANGE_SET(PRE_EMPHASIS_MID_RANGE)); + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x0b, + CLOCK_LANE_VOD_RANGE_SET_MASK, + CLOCK_LANE_VOD_RANGE_SET(VOD_MAX_RANGE)); } /* Enable PLL and LDO */ phy_update_bits(inno, REGISTER_PART_ANALOG, 0x01, @@ -518,10 +576,25 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) T_TA_WAIT_CNT(ta_wait)); } - /* Enable all lanes on analog part */ + /* Enable lanes on analog part */ + switch (inno->pdata->max_lanes) { + case 1: + val = LANE_EN_0; + break; + case 2: + val = LANE_EN_0 | LANE_EN_1; + break; + case 3: + val = LANE_EN_0 | LANE_EN_1 | LANE_EN_2; + break; + case 4: + default: + val = LANE_EN_0 | LANE_EN_1 | LANE_EN_2 | LANE_EN_3; + break; + } + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00, - LANE_EN_MASK, LANE_EN_CK | LANE_EN_3 | LANE_EN_2 | - LANE_EN_1 | LANE_EN_0); + LANE_EN_MASK, LANE_EN_CK | val); } static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno) @@ -680,12 +753,21 @@ static const struct inno_video_phy_plat_data max_1ghz_video_phy_plat_data = { .inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_1ghz, .num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_1ghz), .max_rate = MAX_1GHZ, + .max_lanes = 4, +}; + +static const struct inno_video_phy_plat_data max_1_5ghz_video_phy_plat_data = { + .inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_1_5ghz, + .num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_1_5ghz), + .max_rate = MAX_1_5GHZ, + .max_lanes = 2, }; static const struct inno_video_phy_plat_data max_2_5ghz_video_phy_plat_data = { .inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_2_5ghz, .num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_2_5ghz), .max_rate = MAX_2_5GHZ, + .max_lanes = 4, }; static int inno_dsidphy_probe(struct platform_device *pdev) @@ -768,6 +850,9 @@ static const struct of_device_id inno_dsidphy_of_match[] = { .compatible = "rockchip,rk3368-dsi-dphy", .data = &max_1ghz_video_phy_plat_data, }, { + .compatible = "rockchip,rk3506-dsi-dphy", + .data = &max_1_5ghz_video_phy_plat_data, + }, { .compatible = "rockchip,rk3568-dsi-dphy", .data = &max_2_5ghz_video_phy_plat_data, }, { diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index a3ef19807b9e..7f8fc8e6d489 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -21,6 +21,9 @@ #define REF_CLOCK_100MHz (100 * HZ_PER_MHZ) /* RK3528 COMBO PHY REG */ +#define RK3528_PHYREG5 0x14 +#define RK3528_PHYREG5_GATE_TX_PCK_SEL BIT(3) +#define RK3528_PHYREG5_GATE_TX_PCK_DLY_PLL_OFF BIT(3) #define RK3528_PHYREG6 0x18 #define RK3528_PHYREG6_PLL_KVCO GENMASK(12, 10) #define RK3528_PHYREG6_PLL_KVCO_VALUE 0x2 @@ -103,6 +106,10 @@ #define RK3568_PHYREG18 0x44 #define RK3568_PHYREG18_PLL_LOOP 0x32 +#define RK3568_PHYREG30 0x74 +#define RK3568_PHYREG30_GATE_TX_PCK_SEL BIT(7) +#define RK3568_PHYREG30_GATE_TX_PCK_DLY_PLL_OFF BIT(7) + #define RK3568_PHYREG32 0x7C #define RK3568_PHYREG32_SSC_MASK GENMASK(7, 4) #define RK3568_PHYREG32_SSC_DIR_MASK GENMASK(5, 4) @@ -504,6 +511,10 @@ static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_100MHz: rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { + /* Gate_tx_pck_sel length select for L1ss support */ + rockchip_combphy_updatel(priv, RK3528_PHYREG5_GATE_TX_PCK_SEL, + RK3528_PHYREG5_GATE_TX_PCK_DLY_PLL_OFF, RK3528_PHYREG5); + /* PLL KVCO tuning fine */ val = FIELD_PREP(RK3528_PHYREG6_PLL_KVCO, RK3528_PHYREG6_PLL_KVCO_VALUE); rockchip_combphy_updatel(priv, RK3528_PHYREG6_PLL_KVCO, val, @@ -657,6 +668,10 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_100MHz: rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { + /* Gate_tx_pck_sel length select for L1ss support */ + rockchip_combphy_updatel(priv, RK3568_PHYREG30_GATE_TX_PCK_SEL, + RK3568_PHYREG30_GATE_TX_PCK_DLY_PLL_OFF, + RK3568_PHYREG30); /* PLL KVCO tuning fine */ val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, RK3568_PHYREG33_PLL_KVCO_VALUE); diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index 01bbf668e05e..29de2f7bdae8 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -500,9 +500,7 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = { REG_SEQ0(CMN_REG(0043), 0x00), REG_SEQ0(CMN_REG(0044), 0x46), REG_SEQ0(CMN_REG(0045), 0x24), - REG_SEQ0(CMN_REG(0046), 0xff), REG_SEQ0(CMN_REG(0047), 0x00), - REG_SEQ0(CMN_REG(0048), 0x44), REG_SEQ0(CMN_REG(0049), 0xfa), REG_SEQ0(CMN_REG(004a), 0x08), REG_SEQ0(CMN_REG(004b), 0x00), @@ -575,6 +573,8 @@ static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = { REG_SEQ0(CMN_REG(0034), 0x00), REG_SEQ0(CMN_REG(003d), 0x40), REG_SEQ0(CMN_REG(0042), 0x78), + REG_SEQ0(CMN_REG(0046), 0xdd), + REG_SEQ0(CMN_REG(0048), 0x11), REG_SEQ0(CMN_REG(004e), 0x34), REG_SEQ0(CMN_REG(005c), 0x25), REG_SEQ0(CMN_REG(005e), 0x4f), @@ -668,13 +668,9 @@ static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = { static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = { REG_SEQ0(LANE_REG(0312), 0x00), - REG_SEQ0(LANE_REG(031e), 0x00), REG_SEQ0(LANE_REG(0412), 0x00), - REG_SEQ0(LANE_REG(041e), 0x00), REG_SEQ0(LANE_REG(0512), 0x00), - REG_SEQ0(LANE_REG(051e), 0x00), REG_SEQ0(LANE_REG(0612), 0x00), - REG_SEQ0(LANE_REG(061e), 0x08), REG_SEQ0(LANE_REG(0303), 0x2f), REG_SEQ0(LANE_REG(0403), 0x2f), REG_SEQ0(LANE_REG(0503), 0x2f), @@ -687,6 +683,11 @@ static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = { REG_SEQ0(LANE_REG(0406), 0x1c), REG_SEQ0(LANE_REG(0506), 0x1c), REG_SEQ0(LANE_REG(0606), 0x1c), + /* Keep Inter-Pair Skew in the limits */ + REG_SEQ0(LANE_REG(031e), 0x02), + REG_SEQ0(LANE_REG(041e), 0x02), + REG_SEQ0(LANE_REG(051e), 0x02), + REG_SEQ0(LANE_REG(061e), 0x0a), }; static struct tx_drv_ctrl tx_drv_ctrl_rbr[4][4] = { @@ -1037,7 +1038,8 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx) ret = rk_hdptx_post_enable_pll(hdptx); if (!ret) - hdptx->hw_rate = hdptx->hdmi_cfg.tmds_char_rate; + hdptx->hw_rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, + hdptx->hdmi_cfg.bpc); return ret; } @@ -1895,19 +1897,20 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with * a different rate argument. */ - return hdptx->hdmi_cfg.tmds_char_rate; + return DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, hdptx->hdmi_cfg.bpc); } static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + unsigned long long tmds_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8); /* Revert any unlikely TMDS char rate change since round_rate() */ - if (hdptx->hdmi_cfg.tmds_char_rate != rate) { - dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n", - rate, hdptx->hdmi_cfg.tmds_char_rate); - hdptx->hdmi_cfg.tmds_char_rate = rate; + if (hdptx->hdmi_cfg.tmds_char_rate != tmds_rate) { + dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n", + tmds_rate, hdptx->hdmi_cfg.tmds_char_rate); + hdptx->hdmi_cfg.tmds_char_rate = tmds_rate; } /* diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index a88ba95bdc8f..1c8bf80119f1 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -1823,7 +1823,7 @@ static int exynos5_usbdrd_orien_sw_set(struct typec_switch_dev *sw, phy_drd->orientation = orientation; } - clk_bulk_disable(phy_drd->drv_data->n_clks, phy_drd->clks); + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); return 0; } diff --git a/drivers/phy/samsung/phy-gs101-ufs.c b/drivers/phy/samsung/phy-gs101-ufs.c index 17b798da5b57..a15e1f453f7f 100644 --- a/drivers/phy/samsung/phy-gs101-ufs.c +++ b/drivers/phy/samsung/phy-gs101-ufs.c @@ -108,12 +108,39 @@ static const struct samsung_ufs_phy_cfg tensor_gs101_post_pwr_hs_config[] = { END_UFS_PHY_CFG, }; +static const struct samsung_ufs_phy_cfg tensor_gs101_post_h8_enter[] = { + PHY_TRSV_REG_CFG_GS101(0x262, 0x08, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x265, 0x0A, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x1, 0x8, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x0, 0x86, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x8, 0x60, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG_GS101(0x222, 0x08, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG_GS101(0x246, 0x01, PWR_MODE_HS_ANY), + END_UFS_PHY_CFG, +}; + +static const struct samsung_ufs_phy_cfg tensor_gs101_pre_h8_exit[] = { + PHY_COMN_REG_CFG(0x0, 0xC6, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x1, 0x0C, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x262, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x265, 0x00, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x8, 0xE0, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG_GS101(0x246, 0x03, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG_GS101(0x222, 0x18, PWR_MODE_HS_ANY), + END_UFS_PHY_CFG, +}; + static const struct samsung_ufs_phy_cfg *tensor_gs101_ufs_phy_cfgs[CFG_TAG_MAX] = { [CFG_PRE_INIT] = tensor_gs101_pre_init_cfg, [CFG_PRE_PWR_HS] = tensor_gs101_pre_pwr_hs_config, [CFG_POST_PWR_HS] = tensor_gs101_post_pwr_hs_config, }; +static const struct samsung_ufs_phy_cfg *tensor_gs101_hibern8_cfgs[] = { + [CFG_POST_HIBERN8_ENTER] = tensor_gs101_post_h8_enter, + [CFG_PRE_HIBERN8_EXIT] = tensor_gs101_pre_h8_exit, +}; + static const char * const tensor_gs101_ufs_phy_clks[] = { "ref_clk", }; @@ -170,6 +197,7 @@ static int gs101_phy_wait_for_cdr_lock(struct phy *phy, u8 lane) const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy = { .cfgs = tensor_gs101_ufs_phy_cfgs, + .cfgs_hibern8 = tensor_gs101_hibern8_cfgs, .isol = { .offset = TENSOR_GS101_PHY_CTRL, .mask = TENSOR_GS101_PHY_CTRL_MASK, diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c index f3cbe6b17b23..ee665f26c236 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.c +++ b/drivers/phy/samsung/phy-samsung-ufs.c @@ -217,6 +217,44 @@ static int samsung_ufs_phy_set_mode(struct phy *generic_phy, return 0; } +static int samsung_ufs_phy_notify_state(struct phy *phy, + union phy_notify state) +{ + struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); + const struct samsung_ufs_phy_cfg *cfg; + int i, err = -EINVAL; + + if (!ufs_phy->cfgs_hibern8) + return 0; + + if (state.ufs_state == PHY_UFS_HIBERN8_ENTER) + cfg = ufs_phy->cfgs_hibern8[CFG_POST_HIBERN8_ENTER]; + else if (state.ufs_state == PHY_UFS_HIBERN8_EXIT) + cfg = ufs_phy->cfgs_hibern8[CFG_PRE_HIBERN8_EXIT]; + else + goto err_out; + + for_each_phy_cfg(cfg) { + for_each_phy_lane(ufs_phy, i) { + samsung_ufs_phy_config(ufs_phy, cfg, i); + } + } + + if (state.ufs_state == PHY_UFS_HIBERN8_EXIT) { + for_each_phy_lane(ufs_phy, i) { + if (ufs_phy->drvdata->wait_for_cdr) { + err = ufs_phy->drvdata->wait_for_cdr(phy, i); + if (err) + goto err_out; + } + } + } + + return 0; +err_out: + return err; +} + static int samsung_ufs_phy_exit(struct phy *phy) { struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); @@ -233,6 +271,7 @@ static const struct phy_ops samsung_ufs_phy_ops = { .power_off = samsung_ufs_phy_power_off, .calibrate = samsung_ufs_phy_calibrate, .set_mode = samsung_ufs_phy_set_mode, + .notify_phystate = samsung_ufs_phy_notify_state, .owner = THIS_MODULE, }; @@ -287,6 +326,7 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev) phy->dev = dev; phy->drvdata = drvdata; phy->cfgs = drvdata->cfgs; + phy->cfgs_hibern8 = drvdata->cfgs_hibern8; memcpy(&phy->isol, &drvdata->isol, sizeof(phy->isol)); if (!of_property_read_u32_index(dev->of_node, "samsung,pmu-syscon", 1, diff --git a/drivers/phy/samsung/phy-samsung-ufs.h b/drivers/phy/samsung/phy-samsung-ufs.h index a28f148081d1..f2c2e744e5ba 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.h +++ b/drivers/phy/samsung/phy-samsung-ufs.h @@ -92,6 +92,11 @@ enum { CFG_TAG_MAX, }; +enum { + CFG_POST_HIBERN8_ENTER, + CFG_PRE_HIBERN8_EXIT, +}; + struct samsung_ufs_phy_cfg { u32 off_0; u32 off_1; @@ -108,6 +113,7 @@ struct samsung_ufs_phy_pmu_isol { struct samsung_ufs_phy_drvdata { const struct samsung_ufs_phy_cfg **cfgs; + const struct samsung_ufs_phy_cfg **cfgs_hibern8; struct samsung_ufs_phy_pmu_isol isol; const char * const *clk_list; int num_clks; @@ -124,6 +130,7 @@ struct samsung_ufs_phy { struct clk_bulk_data *clks; const struct samsung_ufs_phy_drvdata *drvdata; const struct samsung_ufs_phy_cfg * const *cfgs; + const struct samsung_ufs_phy_cfg * const *cfgs_hibern8; struct samsung_ufs_phy_pmu_isol isol; u8 lane_cnt; int ufs_phy_state; diff --git a/drivers/phy/sophgo/phy-cv1800-usb2.c b/drivers/phy/sophgo/phy-cv1800-usb2.c index 64f8e37b4b52..6fe846534e9c 100644 --- a/drivers/phy/sophgo/phy-cv1800-usb2.c +++ b/drivers/phy/sophgo/phy-cv1800-usb2.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> #include <linux/regmap.h> diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 50adabb867cb..6cfe2538d15b 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -341,7 +341,7 @@ static struct phy *phy_gmii_sel_of_xlate(struct device *dev, if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && args->args_count < 2) return ERR_PTR(-EINVAL); - if (phy_id > priv->num_ports) + if (phy_id < 1 || phy_id > priv->num_ports) return ERR_PTR(-EINVAL); if (phy_id != priv->if_phys[phy_id - 1].id) return ERR_PTR(-EINVAL); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 4f8507ebbdac..bc7f37afc48b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -486,6 +486,15 @@ config PINCTRL_PIC32MZDA def_bool y if PIC32MZDA select PINCTRL_PIC32 +config PINCTRL_PIC64GX + bool "pic64gx gpio2 pinctrl driver" + depends on ARCH_MICROCHIP || COMPILE_TEST + depends on OF + select GENERIC_PINCONF + default y + help + This selects the pinctrl driver for gpio2 on pic64gx. + config PINCTRL_PISTACHIO bool "IMG Pistachio SoC pinctrl driver" depends on OF && (MIPS || COMPILE_TEST) @@ -497,6 +506,15 @@ config PINCTRL_PISTACHIO help This support pinctrl and GPIO driver for IMG Pistachio SoC. +config PINCTRL_POLARFIRE_SOC + bool "Polarfire SoC pinctrl driver" + depends on ARCH_MICROCHIP || COMPILE_TEST + depends on OF + select GENERIC_PINCONF + default y + help + This selects the pinctrl driver for Microchip Polarfire SoC. + config PINCTRL_RK805 tristate "Pinctrl and GPIO driver for RK805 PMIC" depends on MFD_RK8XX @@ -686,6 +704,7 @@ source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" source "drivers/pinctrl/berlin/Kconfig" source "drivers/pinctrl/cirrus/Kconfig" +source "drivers/pinctrl/cix/Kconfig" source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/intel/Kconfig" source "drivers/pinctrl/mediatek/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index e0cfb9b7c99b..be5200c23e60 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -48,7 +48,9 @@ obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o obj-$(CONFIG_PINCTRL_PEF2256) += pinctrl-pef2256.o obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o +obj-$(CONFIG_PINCTRL_PIC64GX) += pinctrl-pic64gx-gpio2.o obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o +obj-$(CONFIG_PINCTRL_POLARFIRE_SOC) += pinctrl-mpfs-iomux0.o obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_RP1) += pinctrl-rp1.o @@ -69,6 +71,7 @@ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-y += bcm/ obj-$(CONFIG_PINCTRL_BERLIN) += berlin/ obj-y += cirrus/ +obj-y += cix/ obj-y += freescale/ obj-$(CONFIG_X86) += intel/ obj-y += mediatek/ diff --git a/drivers/pinctrl/cix/Kconfig b/drivers/pinctrl/cix/Kconfig new file mode 100644 index 000000000000..1529b1af6388 --- /dev/null +++ b/drivers/pinctrl/cix/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +config PINCTRL_SKY1_BASE + tristate + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select REGMAP + +config PINCTRL_SKY1 + tristate "Cix Sky1 pinctrl driver" + depends on ARCH_CIX || COMPILE_TEST + depends on HAS_IOMEM + select PINCTRL_SKY1_BASE + help + Say Y here to enable the sky1 pinctrl driver diff --git a/drivers/pinctrl/cix/Makefile b/drivers/pinctrl/cix/Makefile new file mode 100644 index 000000000000..22685d6a107b --- /dev/null +++ b/drivers/pinctrl/cix/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +# Cix Sky1 pin control drivers +obj-$(CONFIG_PINCTRL_SKY1_BASE) += pinctrl-sky1-base.o +obj-$(CONFIG_PINCTRL_SKY1) += pinctrl-sky1.o diff --git a/drivers/pinctrl/cix/pinctrl-sky1-base.c b/drivers/pinctrl/cix/pinctrl-sky1-base.c new file mode 100644 index 000000000000..a5b583f10441 --- /dev/null +++ b/drivers/pinctrl/cix/pinctrl-sky1-base.c @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Author: Jerry Zhu <Jerry.Zhu@cixtech.com> +// Author: Gary Yang <gary.yang@cixtech.com> + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#include "../core.h" +#include "../pinconf.h" +#include "../pinctrl-utils.h" +#include "../pinmux.h" +#include "pinctrl-sky1.h" + +#define SKY1_PIN_SIZE (4) +#define SKY1_MUX_MASK GENMASK(8, 7) +#define SKY1_MUX_SHIFT (7) +#define SKY1_PULLCONF_MASK GENMASK(6, 5) +#define SKY1_PULLUP_BIT (6) +#define SKY1_PULLDN_BIT (5) +#define SKY1_DS_MASK GENMASK(3, 0) + +#define CIX_PIN_NO_SHIFT (8) +#define CIX_PIN_FUN_MASK GENMASK(1, 0) +#define CIX_GET_PIN_NO(x) ((x) >> CIX_PIN_NO_SHIFT) +#define CIX_GET_PIN_FUNC(x) ((x) & CIX_PIN_FUN_MASK) +#define SKY1_DEFAULT_DS_VAL (4) + +static const char * const sky1_gpio_functions[] = { + "func0", "func1", "func2", "func3", +}; + +static unsigned char sky1_ds_table[] = { + 2, 3, 5, 6, 8, 9, 11, 12, 13, 14, 17, 18, 20, 21, 23, 24, +}; + +static bool sky1_pctrl_is_function_valid(struct sky1_pinctrl *spctl, + u32 pin_num, u32 fnum) +{ + int i; + + for (i = 0; i < spctl->info->npins; i++) { + const struct sky1_pin_desc *pin = spctl->info->pins + i; + + if (pin->pin.number == pin_num) { + if (fnum < pin->nfunc) + return true; + + break; + } + } + + return false; +} + +static int sky1_pctrl_dt_node_to_map_func(struct sky1_pinctrl *spctl, + u32 pin, u32 fnum, struct sky1_pinctrl_group *grp, + struct pinctrl_map **map, unsigned int *reserved_maps, + unsigned int *num_maps) +{ + bool ret; + + if (*num_maps == *reserved_maps) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = grp->name; + + ret = sky1_pctrl_is_function_valid(spctl, pin, fnum); + if (!ret) { + dev_err(spctl->dev, "invalid function %d on pin %d .\n", + fnum, pin); + return -EINVAL; + } + + (*map)[*num_maps].data.mux.function = sky1_gpio_functions[fnum]; + (*num_maps)++; + + return 0; +} + +static struct sky1_pinctrl_group * +sky1_pctrl_find_group_by_pin(struct sky1_pinctrl *spctl, u32 pin) +{ + int i; + + for (i = 0; i < spctl->info->npins; i++) { + struct sky1_pinctrl_group *grp = + (struct sky1_pinctrl_group *)spctl->groups + i; + + if (grp->pin == pin) + return grp; + } + + return NULL; +} + +static int sky1_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *node, + struct pinctrl_map **map, + unsigned int *reserved_maps, + unsigned int *num_maps) +{ + struct property *pins; + u32 pinfunc, pin, func; + int num_pins, num_funcs, maps_per_pin; + unsigned long *configs; + unsigned int num_configs; + bool has_config = false; + int i, err; + unsigned int reserve = 0; + struct sky1_pinctrl_group *grp; + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + + pins = of_find_property(node, "pinmux", NULL); + if (!pins) { + dev_err(spctl->dev, "missing pins property in node %pOFn .\n", + node); + return -EINVAL; + } + + err = pinconf_generic_parse_dt_config(node, pctldev, &configs, + &num_configs); + if (err) + return err; + + if (num_configs) + has_config = true; + + num_pins = pins->length / sizeof(u32); + num_funcs = num_pins; + maps_per_pin = 0; + if (num_funcs) + maps_per_pin++; + if (has_config && num_pins >= 1) + maps_per_pin++; + + if (!num_pins || !maps_per_pin) { + err = -EINVAL; + goto exit; + } + + reserve = num_pins * maps_per_pin; + + err = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, num_maps, reserve); + if (err < 0) + goto exit; + + for (i = 0; i < num_pins; i++) { + err = of_property_read_u32_index(node, "pinmux", + i, &pinfunc); + if (err) + goto exit; + + pin = CIX_GET_PIN_NO(pinfunc); + func = CIX_GET_PIN_FUNC(pinfunc); + pctldev->num_functions = ARRAY_SIZE(sky1_gpio_functions); + + if (pin >= pctldev->desc->npins || + func >= pctldev->num_functions) { + dev_err(spctl->dev, "invalid pins value.\n"); + err = -EINVAL; + goto exit; + } + + grp = sky1_pctrl_find_group_by_pin(spctl, pin); + if (!grp) { + dev_err(spctl->dev, "unable to match pin %d to group\n", + pin); + err = -EINVAL; + goto exit; + } + + err = sky1_pctrl_dt_node_to_map_func(spctl, pin, func, grp, + map, reserved_maps, num_maps); + if (err < 0) + goto exit; + + if (has_config) { + err = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, num_maps, grp->name, + configs, num_configs, + PIN_MAP_TYPE_CONFIGS_GROUP); + if (err < 0) + goto exit; + } + } + + err = 0; + +exit: + kfree(configs); + return err; +} + +static int sky1_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned int *num_maps) +{ + unsigned int reserved_maps; + int ret; + + *map = NULL; + *num_maps = 0; + reserved_maps = 0; + + for_each_child_of_node_scoped(np_config, np) { + ret = sky1_pctrl_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) { + pinctrl_utils_free_map(pctldev, *map, *num_maps); + return ret; + } + } + + return 0; +} + +static void sky1_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned int num_maps) +{ + kfree(map); +} + +static int sky1_pctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + + return spctl->info->npins; +} + +static const char *sky1_pctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + + return spctl->groups[group].name; +} + +static int sky1_pctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + + *pins = (unsigned int *)&spctl->groups[group].pin; + *num_pins = 1; + + return 0; +} + +static void sky1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned int offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static const struct pinctrl_ops sky1_pctrl_ops = { + .dt_node_to_map = sky1_pctrl_dt_node_to_map, + .dt_free_map = sky1_dt_free_map, + .get_groups_count = sky1_pctrl_get_groups_count, + .get_group_name = sky1_pctrl_get_group_name, + .get_group_pins = sky1_pctrl_get_group_pins, + .pin_dbg_show = sky1_pin_dbg_show, +}; + +static int sky1_pmx_set_one_pin(struct sky1_pinctrl *spctl, + unsigned int pin, unsigned char muxval) +{ + u32 reg_val; + void __iomem *pin_reg; + + pin_reg = spctl->base + pin * SKY1_PIN_SIZE; + reg_val = readl(pin_reg); + reg_val &= ~SKY1_MUX_MASK; + reg_val |= muxval << SKY1_MUX_SHIFT; + writel(reg_val, pin_reg); + + dev_dbg(spctl->dev, "write: offset 0x%x val 0x%x\n", + pin * SKY1_PIN_SIZE, reg_val); + return 0; +} + +static int sky1_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, + unsigned int group) +{ + bool ret; + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + struct sky1_pinctrl_group *g = + (struct sky1_pinctrl_group *)spctl->groups + group; + + ret = sky1_pctrl_is_function_valid(spctl, g->pin, function); + if (!ret) { + dev_err(spctl->dev, "invalid function %d on group %d .\n", + function, group); + return -EINVAL; + } + + sky1_pmx_set_one_pin(spctl, g->pin, function); + return 0; +} + +static int sky1_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(sky1_gpio_functions); +} + +static const char *sky1_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return sky1_gpio_functions[selector]; +} + +static int sky1_pmx_get_func_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char * const **groups, + unsigned int * const num_groups) +{ + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + const struct sky1_pinctrl_soc_info *info = spctl->info; + + *groups = spctl->grp_names; + *num_groups = info->npins; + + return 0; +} + +static const struct pinmux_ops sky1_pmx_ops = { + .get_functions_count = sky1_pmx_get_funcs_cnt, + .get_function_groups = sky1_pmx_get_func_groups, + .get_function_name = sky1_pmx_get_func_name, + .set_mux = sky1_pmx_set_mux, +}; + +static int sky1_pconf_set_pull_select(struct sky1_pinctrl *spctl, + unsigned int pin, bool enable, bool isup) +{ + u32 reg_val, reg_pullsel = 0; + void __iomem *pin_reg; + + pin_reg = spctl->base + pin * SKY1_PIN_SIZE; + reg_val = readl(pin_reg); + reg_val &= ~SKY1_PULLCONF_MASK; + + if (!enable) + goto update; + + if (isup) + reg_pullsel = BIT(SKY1_PULLUP_BIT); + else + reg_pullsel = BIT(SKY1_PULLDN_BIT); + +update: + reg_val |= reg_pullsel; + writel(reg_val, pin_reg); + + dev_dbg(spctl->dev, "write: offset 0x%x val 0x%x\n", + pin * SKY1_PIN_SIZE, reg_val); + return 0; +} + +static int sky1_ds_to_index(unsigned char driving) +{ + int i; + + for (i = 0; i < sizeof(sky1_ds_table); i++) + if (driving == sky1_ds_table[i]) + return i; + return SKY1_DEFAULT_DS_VAL; +} + +static int sky1_pconf_set_driving(struct sky1_pinctrl *spctl, + unsigned int pin, unsigned char driving) +{ + unsigned int reg_val, val; + void __iomem *pin_reg; + + if (pin >= spctl->info->npins) + return -EINVAL; + + pin_reg = spctl->base + pin * SKY1_PIN_SIZE; + reg_val = readl(pin_reg); + reg_val &= ~SKY1_DS_MASK; + val = sky1_ds_to_index(driving); + reg_val |= (val & SKY1_DS_MASK); + writel(reg_val, pin_reg); + + dev_dbg(spctl->dev, "write: offset 0x%x val 0x%x\n", + pin * SKY1_PIN_SIZE, reg_val); + + return 0; +} + +static int sky1_pconf_parse_conf(struct pinctrl_dev *pctldev, + unsigned int pin, enum pin_config_param param, + enum pin_config_param arg) +{ + int ret = 0; + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + ret = sky1_pconf_set_pull_select(spctl, pin, false, false); + break; + case PIN_CONFIG_BIAS_PULL_UP: + ret = sky1_pconf_set_pull_select(spctl, pin, true, true); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = sky1_pconf_set_pull_select(spctl, pin, true, false); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + ret = sky1_pconf_set_driving(spctl, pin, arg); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int sky1_pconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, + unsigned long *config) +{ + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + struct sky1_pinctrl_group *g = &spctl->groups[group]; + + *config = g->config; + + return 0; +} + +static int sky1_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int group, + unsigned long *configs, unsigned int num_configs) +{ + struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev); + struct sky1_pinctrl_group *g = &spctl->groups[group]; + int i, ret; + + for (i = 0; i < num_configs; i++) { + ret = sky1_pconf_parse_conf(pctldev, g->pin, + pinconf_to_config_param(configs[i]), + pinconf_to_config_argument(configs[i])); + if (ret < 0) + return ret; + + g->config = configs[i]; + } + + return 0; +} + +static const struct pinconf_ops sky1_pinconf_ops = { + .pin_config_group_get = sky1_pconf_group_get, + .pin_config_group_set = sky1_pconf_group_set, +}; + +static int sky1_pctrl_build_state(struct platform_device *pdev) +{ + struct sky1_pinctrl *spctl = platform_get_drvdata(pdev); + const struct sky1_pinctrl_soc_info *info = spctl->info; + int i; + + /* Allocate groups */ + spctl->groups = devm_kcalloc(&pdev->dev, info->npins, + sizeof(*spctl->groups), GFP_KERNEL); + if (!spctl->groups) + return -ENOMEM; + + /* We assume that one pin is one group, use pin name as group name. */ + spctl->grp_names = devm_kcalloc(&pdev->dev, info->npins, + sizeof(*spctl->grp_names), GFP_KERNEL); + if (!spctl->grp_names) + return -ENOMEM; + + for (i = 0; i < info->npins; i++) { + const struct sky1_pin_desc *pin = spctl->info->pins + i; + struct sky1_pinctrl_group *group = + (struct sky1_pinctrl_group *)spctl->groups + i; + + group->name = pin->pin.name; + group->pin = pin->pin.number; + spctl->grp_names[i] = pin->pin.name; + } + + return 0; +} + +int sky1_base_pinctrl_probe(struct platform_device *pdev, + const struct sky1_pinctrl_soc_info *info) +{ + struct pinctrl_desc *sky1_pinctrl_desc; + struct sky1_pinctrl *spctl; + struct pinctrl_pin_desc *pins; + int ret, i; + + if (!info || !info->pins || !info->npins) { + dev_err(&pdev->dev, "wrong pinctrl info\n"); + return -EINVAL; + } + + /* Create state holders etc for this driver */ + spctl = devm_kzalloc(&pdev->dev, sizeof(*spctl), GFP_KERNEL); + if (!spctl) + return -ENOMEM; + + spctl->info = info; + platform_set_drvdata(pdev, spctl); + + spctl->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(spctl->base)) + return PTR_ERR(spctl->base); + + sky1_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*sky1_pinctrl_desc), + GFP_KERNEL); + if (!sky1_pinctrl_desc) + return -ENOMEM; + + pins = devm_kcalloc(&pdev->dev, info->npins, sizeof(*pins), + GFP_KERNEL); + if (!pins) + return -ENOMEM; + for (i = 0; i < info->npins; i++) + pins[i] = info->pins[i].pin; + + ret = sky1_pctrl_build_state(pdev); + if (ret) + return ret; + + sky1_pinctrl_desc->name = dev_name(&pdev->dev); + sky1_pinctrl_desc->pins = pins; + sky1_pinctrl_desc->npins = info->npins; + sky1_pinctrl_desc->pctlops = &sky1_pctrl_ops; + sky1_pinctrl_desc->pmxops = &sky1_pmx_ops; + sky1_pinctrl_desc->confops = &sky1_pinconf_ops; + sky1_pinctrl_desc->owner = THIS_MODULE; + spctl->dev = &pdev->dev; + ret = devm_pinctrl_register_and_init(&pdev->dev, + sky1_pinctrl_desc, spctl, + &spctl->pctl); + if (ret) { + dev_err(&pdev->dev, "could not register SKY1 pinctrl driver\n"); + return ret; + } + + /* + * The SKY1 SoC has two pin controllers: one for normal working state + * and one for sleep state. Since one controller only has working + * states and the other only sleep states, it will seem to the + * controller is always in the first configured state, so no + * transitions between default->sleep->default are detected and no + * new pin states are applied when we go in and out of sleep state. + * + * To counter this, provide dummies, so that the sleep-only pin + * controller still get some default states, and the working state pin + * controller get some sleep states, so that state transitions occur + * and we re-configure pins for default and sleep states. + */ + pinctrl_provide_dummies(); + + dev_dbg(&pdev->dev, "initialized SKY1 pinctrl driver\n"); + + return pinctrl_enable(spctl->pctl); +} +EXPORT_SYMBOL_GPL(sky1_base_pinctrl_probe); + + +MODULE_AUTHOR("Jerry Zhu <Jerry.Zhu@cixtech.com>"); +MODULE_DESCRIPTION("Cix SKy1 pinctrl base driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/cix/pinctrl-sky1.c b/drivers/pinctrl/cix/pinctrl-sky1.c new file mode 100644 index 000000000000..5d0d8be815b2 --- /dev/null +++ b/drivers/pinctrl/cix/pinctrl-sky1.c @@ -0,0 +1,559 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Author: Jerry Zhu <Jerry.Zhu@cixtech.com> +// Author: Gary Yang <gary.yang@cixtech.com> + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include "linux/stddef.h" + +#include "../core.h" +#include "pinctrl-sky1.h" + +/* Pad names for the s5 domain pinmux subsystem */ +static const char * const gpio1_group[] = {"GPIO1"}; +static const char * const gpio2_group[] = {"GPIO2"}; +static const char * const gpio3_group[] = {"GPIO3"}; +static const char * const gpio4_group[] = {"GPIO4"}; +static const char * const gpio5_group[] = {"GPIO5"}; +static const char * const gpio6_group[] = {"GPIO6"}; +static const char * const gpio7_group[] = {"GPIO7"}; +static const char * const gpio8_group[] = {"GPIO8"}; +static const char * const gpio9_group[] = {"GPIO9"}; +static const char * const gpio10_group[] = {"GPIO10"}; +static const char * const gpio11_group[] = {"GPIO11"}; +static const char * const gpio12_group[] = {"GPIO12"}; +static const char * const gpio13_group[] = {"GPIO13"}; +static const char * const gpio14_group[] = {"GPIO14"}; +static const char * const rsmrst_group[] = { }; +static const char * const srst_group[] = { }; +static const char * const slp_s3_group[] = { }; +static const char * const slp_s5_group[] = { }; +static const char * const pwrgd_group[] = { }; +static const char * const pwrok_group[] = { }; +static const char * const pwrbtn_group[] = { }; +static const char * const ddrio_gate_group[] = { }; +static const char * const jtag_gpio_group[] = { }; +static const char * const jtag_tck_group[] = { }; +static const char * const jtag_tdi_group[] = { }; +static const char * const jtag_tdo_group[] = { }; +static const char * const tms_group[] = { }; +static const char * const trsl_group[] = { }; +static const char * const sfi_i2c0_scl_group[] = {"SFI_I2C0_SCL", + "SFI_I3C0_SCL"}; +static const char * const sfi_i2c0_sda_group[] = {"SFI_I2C0_SDA", + "SFI_I3C0_SDA"}; +static const char * const sfi_i2c1_scl_group[] = {"SFI_I2C1_SCL", + "SFI_I3C1_SCL", "SFI_SPI_CS0"}; +static const char * const sfi_i2c1_sda_group[] = {"SFI_I2C1_SDA", + "SFI_I3C1_SDA", "SFI_SPI_CS1"}; +static const char * const sfi_gpio0_group[] = {"GPIO15", "SFI_SPI_SCK", + "SFI_GPIO0"}; +static const char * const sfi_gpio1_group[] = {"GPIO16", "SFI_SPI_MOSI", + "SFI_GPIO1"}; +static const char * const sfi_gpio2_group[] = {"GPIO17", "SFI_SPI_MISO", + "SFI_GPIO2"}; +static const char * const gpio18_group[] = {"SFI_GPIO3", "GPIO18"}; +static const char * const gpio19_group[] = {"SFI_GPIO4", "GPIO19"}; +static const char * const gpio20_group[] = {"SFI_GPIO5", "GPIO20"}; +static const char * const gpio21_group[] = {"SFI_GPIO6", "GPIO21"}; +static const char * const gpio22_group[] = {"SFI_GPIO7", "GPIO22"}; +static const char * const gpio23_group[] = {"SFI_GPIO8", "GPIO23", + "SFI_I3C0_PUR_EN_L"}; +static const char * const gpio24_group[] = {"SFI_GPIO9", "GPIO24", + "SFI_I3C1_PUR_EN_L"}; +static const char * const spi1_miso_group[] = {"SPI1_MISO", "GPIO25"}; +static const char * const spi1_cs0_group[] = {"SPI1_CS0", "GPIO26"}; +static const char * const spi1_cs1_group[] = {"SPI1_CS1", "GPIO27"}; +static const char * const spi1_mosi_group[] = {"SPI1_MOSI", "GPIO28"}; +static const char * const spi1_clk_group[] = {"SPI1_CLK", "GPIO29"}; +static const char * const gpio30_group[] = {"GPIO30", "USB_0C0_L"}; +static const char * const gpio31_group[] = {"GPIO31", "USB_0C1_L"}; +static const char * const gpio32_group[] = {"GPIO32", "USB_0C2_L"}; +static const char * const gpio33_group[] = {"GPIO33", "USB_0C3_L"}; +static const char * const gpio34_group[] = {"GPIO34", "USB_0C4_L"}; +static const char * const gpio35_group[] = {"GPIO35", "USB_0C5_L"}; +static const char * const gpio36_group[] = {"GPIO36", "USB_0C6_L"}; +static const char * const gpio37_group[] = {"GPIO37", "USB_0C7_L"}; +static const char * const gpio38_group[] = {"GPIO38", "USB_0C8_L"}; +static const char * const gpio39_group[] = {"GPIO39", "USB_0C9_L"}; +static const char * const gpio40_group[] = {"GPIO40", "USB_DRIVE_VBUS0"}; +static const char * const gpio41_group[] = {"GPIO41", "USB_DRIVE_VBUS4"}; +static const char * const gpio42_group[] = {"GPIO42", "USB_DRIVE_VBUS5"}; +static const char * const se_qspi_clk_group[] = {"SE_QSPI_CLK", "QSPI_CLK"}; +static const char * const se_qspi_cs_group[] = {"SE_QSPI_CS_L", "QSPI_CS_L"}; +static const char * const se_qspi_data0_group[] = {"SE_QSPI_DATA0", + "QSPI_DATA0"}; +static const char * const se_qspi_data1_group[] = {"SE_QSPI_DATA1", + "QSPI_DATA1"}; +static const char * const se_qspi_data2_group[] = {"SE_QSPI_DATA2", + "QSPI_DATA2"}; +static const char * const se_qspi_data3_group[] = {"SE_QSPI_DATA3", + "QSPI_DATA3"}; +static const struct sky1_pin_desc sky1_pinctrl_s5_pads[] = { + SKY_PINFUNCTION(PINCTRL_PIN(0, "GPIO1"), gpio1), + SKY_PINFUNCTION(PINCTRL_PIN(1, "GPIO2"), gpio2), + SKY_PINFUNCTION(PINCTRL_PIN(2, "GPIO3"), gpio3), + SKY_PINFUNCTION(PINCTRL_PIN(3, "GPIO4"), gpio4), + SKY_PINFUNCTION(PINCTRL_PIN(4, "GPIO5"), gpio5), + SKY_PINFUNCTION(PINCTRL_PIN(5, "GPIO6"), gpio6), + SKY_PINFUNCTION(PINCTRL_PIN(6, "GPIO7"), gpio7), + SKY_PINFUNCTION(PINCTRL_PIN(7, "GPIO8"), gpio8), + SKY_PINFUNCTION(PINCTRL_PIN(8, "GPIO9"), gpio9), + SKY_PINFUNCTION(PINCTRL_PIN(9, "GPIO10"), gpio10), + SKY_PINFUNCTION(PINCTRL_PIN(10, "GPIO11"), gpio11), + SKY_PINFUNCTION(PINCTRL_PIN(11, "GPIO12"), gpio12), + SKY_PINFUNCTION(PINCTRL_PIN(12, "GPIO13"), gpio13), + SKY_PINFUNCTION(PINCTRL_PIN(13, "GPIO14"), gpio14), + SKY_PINFUNCTION(PINCTRL_PIN(14, "RSMRST_L"), rsmrst), + SKY_PINFUNCTION(PINCTRL_PIN(15, "SRST_L"), srst), + SKY_PINFUNCTION(PINCTRL_PIN(16, "SLP_S3_L"), slp_s3), + SKY_PINFUNCTION(PINCTRL_PIN(17, "SLP_S5_L"), slp_s5), + SKY_PINFUNCTION(PINCTRL_PIN(18, "PWRGD"), pwrgd), + SKY_PINFUNCTION(PINCTRL_PIN(19, "PWROK"), pwrok), + SKY_PINFUNCTION(PINCTRL_PIN(20, "PWRBTN_L"), pwrbtn), + SKY_PINFUNCTION(PINCTRL_PIN(21, "VDD_DDRIO_GATE"), ddrio_gate), + SKY_PINFUNCTION(PINCTRL_PIN(22, "JTAG_GPIO_L"), jtag_gpio), + SKY_PINFUNCTION(PINCTRL_PIN(23, "JTAG_TCK"), jtag_tck), + SKY_PINFUNCTION(PINCTRL_PIN(24, "JTAG_TDI"), jtag_tdi), + SKY_PINFUNCTION(PINCTRL_PIN(25, "JTAG_TDO"), jtag_tdo), + SKY_PINFUNCTION(PINCTRL_PIN(26, "TMS"), tms), + SKY_PINFUNCTION(PINCTRL_PIN(27, "TRSL_L"), trsl), + SKY_PINFUNCTION(PINCTRL_PIN(28, "SFI_I2C0_SCL"), sfi_i2c0_scl), + SKY_PINFUNCTION(PINCTRL_PIN(29, "SFI_I2C0_SDA"), sfi_i2c0_sda), + SKY_PINFUNCTION(PINCTRL_PIN(30, "SFI_I2C1_SCL"), sfi_i2c1_scl), + SKY_PINFUNCTION(PINCTRL_PIN(31, "SFI_I2C1_SDA"), sfi_i2c1_sda), + SKY_PINFUNCTION(PINCTRL_PIN(32, "SFI_GPIO0"), sfi_gpio0), + SKY_PINFUNCTION(PINCTRL_PIN(33, "SFI_GPIO1"), sfi_gpio1), + SKY_PINFUNCTION(PINCTRL_PIN(34, "SFI_GPIO2"), sfi_gpio2), + SKY_PINFUNCTION(PINCTRL_PIN(35, "GPIO18"), gpio18), + SKY_PINFUNCTION(PINCTRL_PIN(36, "GPIO19"), gpio19), + SKY_PINFUNCTION(PINCTRL_PIN(37, "GPIO20"), gpio20), + SKY_PINFUNCTION(PINCTRL_PIN(38, "GPIO21"), gpio21), + SKY_PINFUNCTION(PINCTRL_PIN(39, "GPIO22"), gpio22), + SKY_PINFUNCTION(PINCTRL_PIN(40, "GPIO23"), gpio23), + SKY_PINFUNCTION(PINCTRL_PIN(41, "GPIO24"), gpio24), + SKY_PINFUNCTION(PINCTRL_PIN(42, "SPI1_MISO"), spi1_miso), + SKY_PINFUNCTION(PINCTRL_PIN(43, "SPI1_CS0"), spi1_cs0), + SKY_PINFUNCTION(PINCTRL_PIN(44, "SPI1_CS1"), spi1_cs1), + SKY_PINFUNCTION(PINCTRL_PIN(45, "SPI1_MOSI"), spi1_mosi), + SKY_PINFUNCTION(PINCTRL_PIN(46, "SPI1_CLK"), spi1_clk), + SKY_PINFUNCTION(PINCTRL_PIN(47, "GPIO30"), gpio30), + SKY_PINFUNCTION(PINCTRL_PIN(48, "GPIO31"), gpio31), + SKY_PINFUNCTION(PINCTRL_PIN(49, "GPIO32"), gpio32), + SKY_PINFUNCTION(PINCTRL_PIN(50, "GPIO33"), gpio33), + SKY_PINFUNCTION(PINCTRL_PIN(51, "GPIO34"), gpio34), + SKY_PINFUNCTION(PINCTRL_PIN(52, "GPIO35"), gpio35), + SKY_PINFUNCTION(PINCTRL_PIN(53, "GPIO36"), gpio36), + SKY_PINFUNCTION(PINCTRL_PIN(54, "GPIO37"), gpio37), + SKY_PINFUNCTION(PINCTRL_PIN(55, "GPIO38"), gpio38), + SKY_PINFUNCTION(PINCTRL_PIN(56, "GPIO39"), gpio39), + SKY_PINFUNCTION(PINCTRL_PIN(57, "GPIO40"), gpio40), + SKY_PINFUNCTION(PINCTRL_PIN(58, "GPIO41"), gpio41), + SKY_PINFUNCTION(PINCTRL_PIN(59, "GPIO42"), gpio42), + SKY_PINFUNCTION(PINCTRL_PIN(60, "SE_QSPI_CLK"), se_qspi_clk), + SKY_PINFUNCTION(PINCTRL_PIN(61, "SE_QSPI_CS_L"), se_qspi_cs), + SKY_PINFUNCTION(PINCTRL_PIN(62, "SE_QSPI_DATA0"), se_qspi_data0), + SKY_PINFUNCTION(PINCTRL_PIN(63, "SE_QSPI_DATA1"), se_qspi_data1), + SKY_PINFUNCTION(PINCTRL_PIN(64, "SE_QSPI_DATA2"), se_qspi_data2), + SKY_PINFUNCTION(PINCTRL_PIN(65, "SE_QSPI_DATA3"), se_qspi_data3), +}; + +/* Pad names for the s0 domain pinmux subsystem */ +static const char * const gpio43_group[] = {"GPIO43"}; +static const char * const gpio44_group[] = {"GPIO44"}; +static const char * const gpio45_group[] = {"GPIO45"}; +static const char * const gpio46_group[] = {"GPIO46"}; +static const char * const reset_in_group[] = { }; +static const char * const plt_reset_group[] = { }; +static const char * const thermtrip_group[] = { }; +static const char * const prochot_group[] = { }; +static const char * const pm_i2c0_clk_group[] = { }; +static const char * const pm_i2c0_data_group[] = { }; +static const char * const pm_i2c1_clk_group[] = { }; +static const char * const pm_i2c1_data_group[] = { }; +static const char * const pm_i2c2_clk_group[] = { }; +static const char * const pm_i2c2_data_group[] = { }; +static const char * const pm_i2c3_clk_group[] = { }; +static const char * const pm_i2c3_data_group[] = { }; +static const char * const strap0_group[] = { }; +static const char * const strap1_group[] = { }; +static const char * const dp2_digon_group[] = {"DP2_DIGON"}; +static const char * const dp2_blon_group[] = {"DP2_BLON"}; +static const char * const dp2_vary_bl_group[] = {"DP2_VARY_BL"}; +static const char * const i2c7_scl_group[] = {"I2C7_SCL"}; +static const char * const i2c7_sda_group[] = {"I2C7_SDA"}; +static const char * const uart6_csu_se_txd_group[] = { }; +static const char * const clk_req1_group[] = { }; +static const char * const clk_req3_group[] = { }; +static const char * const i2c5_scl_group[] = {"I2C5_SCL", "GPIO47"}; +static const char * const i2c5_sda_group[] = {"I2C5_SDA", "GPIO48"}; +static const char * const i2c6_scl_group[] = {"I2C6_SCL", "GPIO49"}; +static const char * const i2c6_sda_group[] = {"I2C6_SDA", "GPIO50"}; +static const char * const i2c0_scl_group[] = {"I2C0_SCL", "GPIO51"}; +static const char * const i2c0_sda_group[] = {"I2C0_SDA", "GPIO52"}; +static const char * const i2c1_scl_group[] = {"I2C1_SCL", "GPIO53"}; +static const char * const i2c1_sda_group[] = {"I2C1_SDA", "GPIO54"}; +static const char * const i2c2_scl_group[] = {"I2C2_SCL", "I3C0_SCL", + "GPIO55"}; +static const char * const i2c2_sda_group[] = {"I2C2_SDA", "I3C0_SDA", + "GPIO56"}; +static const char * const gpio57_group[] = {"GPIO57", "I3C0_PUR_EN_L"}; +static const char * const i2c3_scl_group[] = {"I2C3_SCL", "I3C1_SCL", + "GPIO58"}; +static const char * const i2c3_sda_group[] = {"I2C3_SDA", "I3C1_SDA", + "GPIO59"}; +static const char * const gpio60_group[] = {"GPIO60", "I3C1_PUR_EN_L"}; +static const char * const i2c4_scl_group[] = {"I2C4_SCL", "GPIO61"}; +static const char * const i2c4_sda_group[] = {"I2C4_SDA", "GPIO62"}; +static const char * const hda_bitclk_group[] = {"HDA_BITCLK", "I2S0_SCK", + "I2S9_RSCK_DBG"}; +static const char * const hda_rst_group[] = {"HDA_RST_L", "I2S0_DATA_IN", + "I2S9_DATA_IN_DBG"}; +static const char * const hda_sdin0_group[] = {"HDA_SDIN0", "I2S0_MCLK", + "I2S9_TSCK_DBG"}; +static const char * const hda_sdout0_group[] = {"HDA_SDOUT0", "I2S0_DATA_OUT", + "I2S9_TWS_DBG"}; +static const char * const hda_sync_group[] = {"HDA_SYNC", "I2S0_WS", + "I2S9_RWS_DBG"}; +static const char * const hda_sdin1_group[] = {"HDA_SDIN1", "GPIO63", + "I2S9_DATA_IN1_DBG"}; +static const char * const hda_sdout1_group[] = {"HDA_SDOUT1", "GPIO64", + "I2S9_DATA_OUT0_DBG"}; +static const char * const i2s1_mclk_group[] = {"I2S1_MCLK", "GPIO65"}; +static const char * const i2s1_sck_group[] = {"I2S1_SCK", "GPIO66"}; +static const char * const i2s1_ws_group[] = {"I2S1_WS", "GPIO67"}; +static const char * const i2s1_data_in_group[] = {"I2S1_DATA_IN", "GPIO68"}; +static const char * const i2s1_data_out_group[] = {"I2S1_DATA_OUT", "GPIO69"}; +static const char * const i2s2_mck_group[] = {"I2S2_MCLK", "GPIO70"}; +static const char * const i2s2_rsck_group[] = {"I2S2_RSCK", "GPIO71", + "I2S5_RSCK_DBG", "I2S6_RSCK_DBG"}; +static const char * const i2s2_rws_group[] = {"I2S2_RWS", "GPIO72", + "I2S5_RWS_DBG", "I2S6_RWS_DBG"}; +static const char * const i2s2_tsck_group[] = {"I2S2_TSCK", "GPIO73", + "I2S5_TSCK_DBG", "I2S6_TSCK_DBG"}; +static const char * const i2s2_tws_group[] = {"I2S2_TWS", "GPIO74", + "I2S5_TWS_DBG", "I2S6_TWS_DBG"}; +static const char * const i2s2_data_in0_group[] = {"I2S2_DATA_IN0", "GPIO75", + "I2S5_DATA_IN0_DBG", "I2S6_DATA_IN0_DBG"}; +static const char * const i2s2_data_in1_group[] = {"I2S2_DATA_IN1", "GPIO76", + "I2S5_DATA_IN1_DBG", "I2S6_DATA_IN1_DBG"}; +static const char * const i2s2_data_out0_group[] = {"I2S2_DATA_OUT0", "GPIO77", + "I2S5_DATA_OUT0_DBG", "I2S6_DATA_OUT0_DBG"}; +static const char * const i2s2_data_out1_group[] = {"I2S2_DATA_OUT1", "GPIO78", + "I2S5_DATA_OUT1_DBG", "I2S6_DATA_OUT1_DBG"}; +static const char * const i2s2_data_out2_group[] = {"I2S2_DATA_OUT2", + "GPIO79"}; +static const char * const i2s2_data_out3_group[] = {"I2S2_DATA_OUT3", "GPIO80", + "I2S9_DATA_OUT1_DBG"}; +static const char * const i2s3_mclk_group[] = {"I2S3_MCLK", "GPIO81"}; +static const char * const i2s3_rsck_group[] = {"I2S3_RSCK", "GPIO82", + "I2S7_RSCK_DBG", "I2S8_RSCK_DBG"}; +static const char * const i2s3_rws_group[] = {"I2S3_RWS", "GPIO83", + "I2S7_RWS_DBG", "I2S8_RWS_DBG"}; +static const char * const i2s3_tsck_group[] = {"I2S3_TSCK", "GPIO84", + "I2S7_TSCK_DBG", "I2S8_TSCK_DBG"}; +static const char * const i2s3_tws_group[] = {"I2S3_TWS", "GPIO85", + "I2S7_TWS_DBG", "I2S8_TWS_DBG"}; +static const char * const i2s3_data_in0_group[] = {"I2S3_DATA_IN0", "GPIO86", + "I2S7_DATA_IN0_DBG", "I2S8_DATA_IN0_DBG"}; +static const char * const i2s3_data_in1_group[] = {"I2S3_DATA_IN1", "GPIO87", + "I2S7_DATA_IN1_DBG", "I2S8_DATA_IN1_DBG"}; +static const char * const i2s3_data_out0_group[] = {"I2S3_DATA_OUT0", "GPIO88", + "I2S7_DATA_OUT0_DBG", "I2S8_DATA_OUT0_DBG"}; +static const char * const i2s3_data_out1_group[] = {"I2S3_DATA_OUT1", "GPIO89", + "I2S7_DATA_OUT1_DBG", "I2S8_DATA_OUT1_DBG"}; +static const char * const gpio90_group[] = {"GPIO90", "I2S4_MCLK_LB"}; +static const char * const gpio91_group[] = {"GPIO91", "I2S4_SCK_LB"}; +static const char * const gpio92_group[] = {"GPIO92", "I2S4_WS_LB"}; +static const char * const gpio93_group[] = {"GPIO93", "I2S4_DATA_IN_LB"}; +static const char * const gpio94_group[] = {"GPIO94", "I2S4_DATA_OUT_LB"}; +static const char * const uart0_txd_group[] = {"UART0_TXD", "PWM0", "GPIO95"}; +static const char * const uart0_rxd_group[] = {"UART0_RXD", "PWM1", "GPIO96"}; +static const char * const uart0_cts_group[] = {"UART0_CTS", "FAN_OUT2", + "GPIO97"}; +static const char * const uart0_rts_group[] = {"UART0_RTS", "FAN_TACH2", + "GPIO98"}; +static const char * const uart1_txd_group[] = {"UART1_TXD", "FAN_OUT0", + "GPIO99"}; +static const char * const uart1_rxd_group[] = {"UART1_RXD", "FAN_TACH0", + "GPIO100"}; +static const char * const uart1_cts_group[] = {"UART1_CTS", "FAN_OUT1", + "GPIO101"}; +static const char * const uart1_rts_group[] = {"UART1_RTS", "FAN_TACH1", + "GPIO102"}; +static const char * const uart2_txd_group[] = {"UART2_TXD", "GPIO103"}; +static const char * const uart2_rxd_group[] = {"UART2_RXD", "GPIO104"}; +static const char * const uart3_txd_group[] = {"UART3_TXD", "GPIO105"}; +static const char * const uart3_rxd_group[] = {"UART3_RXD", "GPIO106"}; +static const char * const uart3_cts_group[] = {"UART3_CTS", "GPIO107", + "TRIGIN0"}; +static const char * const uart3_rts_group[] = {"UART3_RTS", "GPIO108", + "TRIGIN1"}; +static const char * const uart4_csu_pm_txd_group[] = {"UART4_CSU_PM_TXD", + "GPIO109"}; +static const char * const uart4_csu_pm_rxd_group[] = {"UART4_CSU_PM_RXD", + "GPIO110"}; +static const char * const uart5_csu_se_txd_group[] = {"UART5_CSU_SE_TXD", + "GPIO111"}; +static const char * const uart5_csu_se_rxd_group[] = {"UART5_CSU_SE_RXD", + "GPIO112"}; +static const char * const uart6_csu_se_rxd_group[] = {"UART6_CSU_SE_RXD", + "GPIO113"}; +static const char * const clk_req0_group[] = {"CLK_REQ0_L", "GPIO114"}; +static const char * const clk_req2_group[] = {"CLK_REQ2_L", "GPIO115"}; +static const char * const clk_req4_group[] = {"CLK_REQ4_L", "GPIO116"}; +static const char * const csi0_mclk0_group[] = {"CSI0_MCLK0", "GPIO117"}; +static const char * const csi0_mclk1_group[] = {"CSI0_MCLK1", "GPIO118"}; +static const char * const csi1_mclk0_group[] = {"CSI1_MCLK0", "GPIO119"}; +static const char * const csi1_mclk1_group[] = {"CSI1_MCLK1", "GPIO120"}; +static const char * const gpio121_group[] = {"GPIO121", "GMAC0_REFCLK_25M"}; +static const char * const gpio122_group[] = {"GPIO122", "GMAC0_TX_CTL"}; +static const char * const gpio123_group[] = {"GPIO123", "GMAC0_TXD0"}; +static const char * const gpio124_group[] = {"GPIO124", "GMAC0_TXD1"}; +static const char * const gpio125_group[] = {"GPIO125", "GMAC0_TXD2"}; +static const char * const gpio126_group[] = {"GPIO126", "GMAC0_TXD3"}; +static const char * const gpio127_group[] = {"GPIO127", "GMAC0_TX_CLK"}; +static const char * const gpio128_group[] = {"GPIO128", "GMAC0_RX_CTL"}; +static const char * const gpio129_group[] = {"GPIO129", "GMAC0_RXD0"}; +static const char * const gpio130_group[] = {"GPIO130", "GMAC0_RXD1"}; +static const char * const gpio131_group[] = {"GPIO131", "GMAC0_RXD2"}; +static const char * const gpio132_group[] = {"GPIO132", "GMAC0_RXD3"}; +static const char * const gpio133_group[] = {"GPIO133", "GMAC0_RX_CLK"}; +static const char * const gpio134_group[] = {"GPIO134", "GMAC0_MDC"}; +static const char * const gpio135_group[] = {"GPIO135", "GMAC0_MDIO"}; +static const char * const gpio136_group[] = {"GPIO136", "GMAC1_REFCLK_25M"}; +static const char * const gpio137_group[] = {"GPIO137", "GMAC1_TX_CTL"}; +static const char * const gpio138_group[] = {"GPIO138", "GMAC1_TXD0", + "SPI2_MISO"}; +static const char * const gpio139_group[] = {"GPIO139", "GMAC1_TXD1", + "SPI2_CS0"}; +static const char * const gpio140_group[] = {"GPIO140", "GMAC1_TXD2", + "SPI2_CS1"}; +static const char * const gpio141_group[] = {"GPIO141", "GMAC1_TXD3", + "SPI2_MOSI"}; +static const char * const gpio142_group[] = {"GPIO142", "GMAC1_TX_CLK", + "SPI2_CLK"}; +static const char * const gpio143_group[] = {"GPIO143", "GMAC1_RX_CTL"}; +static const char * const gpio144_group[] = {"GPIO144", "GMAC1_RXD0"}; +static const char * const gpio145_group[] = {"GPIO145", "GMAC1_RXD1"}; +static const char * const gpio146_group[] = {"GPIO146", "GMAC1_RXD2"}; +static const char * const gpio147_group[] = {"GPIO147", "GMAC1_RXD3"}; +static const char * const gpio148_group[] = {"GPIO148", "GMAC1_RX_CLK"}; +static const char * const gpio149_group[] = {"GPIO149", "GMAC1_MDC"}; +static const char * const gpio150_group[] = {"GPIO150", "GMAC1_MDIO"}; +static const char * const gpio151_group[] = {"GPIO151", "PM_GPIO0"}; +static const char * const gpio152_group[] = {"GPIO152", "PM_GPIO1"}; +static const char * const gpio153_group[] = {"GPIO153", "PM_GPIO2"}; +static const struct sky1_pin_desc sky1_pinctrl_pads[] = { + SKY_PINFUNCTION(PINCTRL_PIN(0, "GPIO43"), gpio43), + SKY_PINFUNCTION(PINCTRL_PIN(1, "GPIO44"), gpio44), + SKY_PINFUNCTION(PINCTRL_PIN(2, "GPIO45"), gpio45), + SKY_PINFUNCTION(PINCTRL_PIN(3, "GPIO46"), gpio46), + SKY_PINFUNCTION(PINCTRL_PIN(4, "RESET_IN_L"), reset_in), + SKY_PINFUNCTION(PINCTRL_PIN(5, "PLT_RESET_L"), plt_reset), + SKY_PINFUNCTION(PINCTRL_PIN(6, "THERMTRIP_L"), thermtrip), + SKY_PINFUNCTION(PINCTRL_PIN(7, "PROCHOT_L"), prochot), + SKY_PINFUNCTION(PINCTRL_PIN(8, "PM_I2C0_CLK"), pm_i2c0_clk), + SKY_PINFUNCTION(PINCTRL_PIN(9, "PM_I2C0_DATA"), pm_i2c0_data), + SKY_PINFUNCTION(PINCTRL_PIN(10, "PM_I2C1_CLK"), pm_i2c1_clk), + SKY_PINFUNCTION(PINCTRL_PIN(11, "PM_I2C1_DATA"), pm_i2c1_data), + SKY_PINFUNCTION(PINCTRL_PIN(12, "PM_I2C2_CLK"), pm_i2c2_clk), + SKY_PINFUNCTION(PINCTRL_PIN(13, "PM_I2C2_DATA"), pm_i2c2_data), + SKY_PINFUNCTION(PINCTRL_PIN(14, "PM_I2C3_CLK"), pm_i2c3_clk), + SKY_PINFUNCTION(PINCTRL_PIN(15, "PM_I2C3_DATA"), pm_i2c3_data), + SKY_PINFUNCTION(PINCTRL_PIN(16, "STRAP0"), strap0), + SKY_PINFUNCTION(PINCTRL_PIN(17, "STRAP1"), strap1), + SKY_PINFUNCTION(PINCTRL_PIN(18, "DP2_DIGON"), dp2_digon), + SKY_PINFUNCTION(PINCTRL_PIN(19, "DP2_BLON"), dp2_blon), + SKY_PINFUNCTION(PINCTRL_PIN(20, "DP2_VARY_BL"), dp2_vary_bl), + SKY_PINFUNCTION(PINCTRL_PIN(21, "I2C7_SCL"), i2c7_scl), + SKY_PINFUNCTION(PINCTRL_PIN(22, "I2C7_SDA"), i2c7_sda), + SKY_PINFUNCTION(PINCTRL_PIN(23, "UART6_CSU_SE_TXD"), uart6_csu_se_txd), + SKY_PINFUNCTION(PINCTRL_PIN(24, "CLK_REQ1_L"), clk_req1), + SKY_PINFUNCTION(PINCTRL_PIN(25, "CLK_REQ3_L"), clk_req3), + SKY_PINFUNCTION(PINCTRL_PIN(26, "I2C5_SCL"), i2c5_scl), + SKY_PINFUNCTION(PINCTRL_PIN(27, "I2C5_SDA"), i2c5_sda), + SKY_PINFUNCTION(PINCTRL_PIN(28, "I2C6_SCL"), i2c6_scl), + SKY_PINFUNCTION(PINCTRL_PIN(29, "I2C6_SDA"), i2c6_sda), + SKY_PINFUNCTION(PINCTRL_PIN(30, "I2C0_CLK"), i2c0_scl), + SKY_PINFUNCTION(PINCTRL_PIN(31, "I2C0_SDA"), i2c0_sda), + SKY_PINFUNCTION(PINCTRL_PIN(32, "I2C1_CLK"), i2c1_scl), + SKY_PINFUNCTION(PINCTRL_PIN(33, "I2C1_SDA"), i2c1_sda), + SKY_PINFUNCTION(PINCTRL_PIN(34, "I2C2_SCL"), i2c2_scl), + SKY_PINFUNCTION(PINCTRL_PIN(35, "I2C2_SDA"), i2c2_sda), + SKY_PINFUNCTION(PINCTRL_PIN(36, "GPIO57"), gpio57), + SKY_PINFUNCTION(PINCTRL_PIN(37, "I2C3_SCL"), i2c3_scl), + SKY_PINFUNCTION(PINCTRL_PIN(38, "I2C3_SDA"), i2c3_sda), + SKY_PINFUNCTION(PINCTRL_PIN(39, "GPIO60"), gpio60), + SKY_PINFUNCTION(PINCTRL_PIN(40, "I2C4_SCL"), i2c4_scl), + SKY_PINFUNCTION(PINCTRL_PIN(41, "I2C4_SDA"), i2c4_sda), + SKY_PINFUNCTION(PINCTRL_PIN(42, "HDA_BITCLK"), hda_bitclk), + SKY_PINFUNCTION(PINCTRL_PIN(43, "HDA_RST_L"), hda_rst), + SKY_PINFUNCTION(PINCTRL_PIN(44, "HDA_SDIN0"), hda_sdin0), + SKY_PINFUNCTION(PINCTRL_PIN(45, "HDA_SDOUT0"), hda_sdout0), + SKY_PINFUNCTION(PINCTRL_PIN(46, "HDA_SYNC"), hda_sync), + SKY_PINFUNCTION(PINCTRL_PIN(47, "HDA_SDIN1"), hda_sdin1), + SKY_PINFUNCTION(PINCTRL_PIN(48, "HDA_SDOUT1"), hda_sdout1), + SKY_PINFUNCTION(PINCTRL_PIN(49, "I2S1_MCLK"), i2s1_mclk), + SKY_PINFUNCTION(PINCTRL_PIN(50, "I2S1_SCK"), i2s1_sck), + SKY_PINFUNCTION(PINCTRL_PIN(51, "I2S1_WS"), i2s1_ws), + SKY_PINFUNCTION(PINCTRL_PIN(52, "I2S1_DATA_IN"), i2s1_data_in), + SKY_PINFUNCTION(PINCTRL_PIN(53, "I2S1_DATA_OUT"), i2s1_data_out), + SKY_PINFUNCTION(PINCTRL_PIN(54, "I2S2_MCLK"), i2s2_mck), + SKY_PINFUNCTION(PINCTRL_PIN(55, "I2S2_RSCK"), i2s2_rsck), + SKY_PINFUNCTION(PINCTRL_PIN(56, "I2S2_RWS"), i2s2_rws), + SKY_PINFUNCTION(PINCTRL_PIN(57, "I2S2_TSCK"), i2s2_tsck), + SKY_PINFUNCTION(PINCTRL_PIN(58, "I2S2_TWS"), i2s2_tws), + SKY_PINFUNCTION(PINCTRL_PIN(59, "I2S2_DATA_IN0"), i2s2_data_in0), + SKY_PINFUNCTION(PINCTRL_PIN(60, "I2S2_DATA_IN1"), i2s2_data_in1), + SKY_PINFUNCTION(PINCTRL_PIN(61, "I2S2_DATA_OUT0"), i2s2_data_out0), + SKY_PINFUNCTION(PINCTRL_PIN(62, "I2S2_DATA_OUT1"), i2s2_data_out1), + SKY_PINFUNCTION(PINCTRL_PIN(63, "I2S2_DATA_OUT2"), i2s2_data_out2), + SKY_PINFUNCTION(PINCTRL_PIN(64, "I2S2_DATA_OUT3"), i2s2_data_out3), + SKY_PINFUNCTION(PINCTRL_PIN(65, "I2S3_MCLK"), i2s3_mclk), + SKY_PINFUNCTION(PINCTRL_PIN(66, "I2S3_RSCK"), i2s3_rsck), + SKY_PINFUNCTION(PINCTRL_PIN(67, "I2S3_RWS"), i2s3_rws), + SKY_PINFUNCTION(PINCTRL_PIN(68, "I2S3_TSCK"), i2s3_tsck), + SKY_PINFUNCTION(PINCTRL_PIN(69, "I2S3_TWS"), i2s3_tws), + SKY_PINFUNCTION(PINCTRL_PIN(70, "I2S3_DATA_IN0"), i2s3_data_in0), + SKY_PINFUNCTION(PINCTRL_PIN(71, "I2S3_DATA_IN1"), i2s3_data_in1), + SKY_PINFUNCTION(PINCTRL_PIN(72, "I2S3_DATA_OUT0"), i2s3_data_out0), + SKY_PINFUNCTION(PINCTRL_PIN(73, "I2S3_DATA_OUT1"), i2s3_data_out1), + SKY_PINFUNCTION(PINCTRL_PIN(74, "GPIO90"), gpio90), + SKY_PINFUNCTION(PINCTRL_PIN(75, "GPIO91"), gpio91), + SKY_PINFUNCTION(PINCTRL_PIN(76, "GPIO92"), gpio92), + SKY_PINFUNCTION(PINCTRL_PIN(77, "GPIO93"), gpio93), + SKY_PINFUNCTION(PINCTRL_PIN(78, "GPIO94"), gpio94), + SKY_PINFUNCTION(PINCTRL_PIN(79, "UART0_TXD"), uart0_txd), + SKY_PINFUNCTION(PINCTRL_PIN(80, "UART0_RXD"), uart0_rxd), + SKY_PINFUNCTION(PINCTRL_PIN(81, "UART0_CTS"), uart0_cts), + SKY_PINFUNCTION(PINCTRL_PIN(82, "UART0_RTS"), uart0_rts), + SKY_PINFUNCTION(PINCTRL_PIN(83, "UART1_TXD"), uart1_txd), + SKY_PINFUNCTION(PINCTRL_PIN(84, "UART1_RXD"), uart1_rxd), + SKY_PINFUNCTION(PINCTRL_PIN(85, "UART1_CTS"), uart1_cts), + SKY_PINFUNCTION(PINCTRL_PIN(86, "UART1_RTS"), uart1_rts), + SKY_PINFUNCTION(PINCTRL_PIN(87, "UART2_TXD"), uart2_txd), + SKY_PINFUNCTION(PINCTRL_PIN(88, "UART2_RXD"), uart2_rxd), + SKY_PINFUNCTION(PINCTRL_PIN(89, "UART3_TXD"), uart3_txd), + SKY_PINFUNCTION(PINCTRL_PIN(90, "UART3_RXD"), uart3_rxd), + SKY_PINFUNCTION(PINCTRL_PIN(91, "UART3_CTS"), uart3_cts), + SKY_PINFUNCTION(PINCTRL_PIN(92, "UART3_RTS"), uart3_rts), + SKY_PINFUNCTION(PINCTRL_PIN(93, "UART4_CSU_PM_TXD"), uart4_csu_pm_txd), + SKY_PINFUNCTION(PINCTRL_PIN(94, "UART4_CSU_PM_RXD"), uart4_csu_pm_rxd), + SKY_PINFUNCTION(PINCTRL_PIN(95, "UART5_CSU_SE_TXD"), uart5_csu_se_txd), + SKY_PINFUNCTION(PINCTRL_PIN(96, "UART5_CSU_SE_RXD"), uart5_csu_se_rxd), + SKY_PINFUNCTION(PINCTRL_PIN(97, "UART6_CSU_SE_RXD"), uart6_csu_se_rxd), + SKY_PINFUNCTION(PINCTRL_PIN(98, "CLK_REQ0_L"), clk_req0), + SKY_PINFUNCTION(PINCTRL_PIN(99, "CLK_REQ2_L"), clk_req2), + SKY_PINFUNCTION(PINCTRL_PIN(100, "CLK_REQ4_L"), clk_req4), + SKY_PINFUNCTION(PINCTRL_PIN(101, "CSI0_MCLK0"), csi0_mclk0), + SKY_PINFUNCTION(PINCTRL_PIN(102, "CSI0_MCLK1"), csi0_mclk1), + SKY_PINFUNCTION(PINCTRL_PIN(103, "CSI1_MCLK0"), csi1_mclk0), + SKY_PINFUNCTION(PINCTRL_PIN(104, "CSI1_MCLK1"), csi1_mclk1), + SKY_PINFUNCTION(PINCTRL_PIN(105, "GPIO121"), gpio121), + SKY_PINFUNCTION(PINCTRL_PIN(106, "GPIO122"), gpio122), + SKY_PINFUNCTION(PINCTRL_PIN(107, "GPIO123"), gpio123), + SKY_PINFUNCTION(PINCTRL_PIN(108, "GPIO124"), gpio124), + SKY_PINFUNCTION(PINCTRL_PIN(109, "GPIO125"), gpio125), + SKY_PINFUNCTION(PINCTRL_PIN(110, "GPIO126"), gpio126), + SKY_PINFUNCTION(PINCTRL_PIN(111, "GPIO127"), gpio127), + SKY_PINFUNCTION(PINCTRL_PIN(112, "GPIO128"), gpio128), + SKY_PINFUNCTION(PINCTRL_PIN(113, "GPIO129"), gpio129), + SKY_PINFUNCTION(PINCTRL_PIN(114, "GPIO130"), gpio130), + SKY_PINFUNCTION(PINCTRL_PIN(115, "GPIO131"), gpio131), + SKY_PINFUNCTION(PINCTRL_PIN(116, "GPIO132"), gpio132), + SKY_PINFUNCTION(PINCTRL_PIN(117, "GPIO133"), gpio133), + SKY_PINFUNCTION(PINCTRL_PIN(118, "GPIO134"), gpio134), + SKY_PINFUNCTION(PINCTRL_PIN(119, "GPIO135"), gpio135), + SKY_PINFUNCTION(PINCTRL_PIN(120, "GPIO136"), gpio136), + SKY_PINFUNCTION(PINCTRL_PIN(121, "GPIO137"), gpio137), + SKY_PINFUNCTION(PINCTRL_PIN(122, "GPIO138"), gpio138), + SKY_PINFUNCTION(PINCTRL_PIN(123, "GPIO139"), gpio139), + SKY_PINFUNCTION(PINCTRL_PIN(124, "GPIO140"), gpio140), + SKY_PINFUNCTION(PINCTRL_PIN(125, "GPIO141"), gpio141), + SKY_PINFUNCTION(PINCTRL_PIN(126, "GPIO142"), gpio142), + SKY_PINFUNCTION(PINCTRL_PIN(127, "GPIO143"), gpio143), + SKY_PINFUNCTION(PINCTRL_PIN(128, "GPIO144"), gpio144), + SKY_PINFUNCTION(PINCTRL_PIN(129, "GPIO145"), gpio145), + SKY_PINFUNCTION(PINCTRL_PIN(130, "GPIO146"), gpio146), + SKY_PINFUNCTION(PINCTRL_PIN(131, "GPIO147"), gpio147), + SKY_PINFUNCTION(PINCTRL_PIN(132, "GPIO148"), gpio148), + SKY_PINFUNCTION(PINCTRL_PIN(133, "GPIO149"), gpio149), + SKY_PINFUNCTION(PINCTRL_PIN(134, "GPIO150"), gpio150), + SKY_PINFUNCTION(PINCTRL_PIN(135, "GPIO151"), gpio151), + SKY_PINFUNCTION(PINCTRL_PIN(136, "GPIO152"), gpio152), + SKY_PINFUNCTION(PINCTRL_PIN(137, "GPIO153"), gpio153), +}; + +static const struct sky1_pinctrl_soc_info sky1_pinctrl_s5_info = { + .pins = sky1_pinctrl_s5_pads, + .npins = ARRAY_SIZE(sky1_pinctrl_s5_pads), +}; + +static const struct sky1_pinctrl_soc_info sky1_pinctrl_info = { + .pins = sky1_pinctrl_pads, + .npins = ARRAY_SIZE(sky1_pinctrl_pads), +}; + +static const struct of_device_id sky1_pinctrl_of_match[] = { + { .compatible = "cix,sky1-pinctrl-s5", .data = &sky1_pinctrl_s5_info, }, + { .compatible = "cix,sky1-pinctrl", .data = &sky1_pinctrl_info, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sky1_pinctrl_of_match); + +static int __maybe_unused sky1_pinctrl_suspend(struct device *dev) +{ + struct sky1_pinctrl *spctl = dev_get_drvdata(dev); + + return pinctrl_force_sleep(spctl->pctl); +} + +static int __maybe_unused sky1_pinctrl_resume(struct device *dev) +{ + struct sky1_pinctrl *spctl = dev_get_drvdata(dev); + + return pinctrl_force_default(spctl->pctl); +} + +const struct dev_pm_ops sky1_pinctrl_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(sky1_pinctrl_suspend, + sky1_pinctrl_resume) +}; +EXPORT_SYMBOL_GPL(sky1_pinctrl_pm_ops); + +static int sky1_pinctrl_probe(struct platform_device *pdev) +{ + const struct sky1_pinctrl_soc_info *pinctrl_info; + + pinctrl_info = device_get_match_data(&pdev->dev); + if (!pinctrl_info) + return -ENODEV; + + return sky1_base_pinctrl_probe(pdev, pinctrl_info); +} + +static struct platform_driver sky1_pinctrl_driver = { + .driver = { + .name = "sky1-pinctrl", + .of_match_table = sky1_pinctrl_of_match, + .pm = &sky1_pinctrl_pm_ops, + }, + .probe = sky1_pinctrl_probe, +}; + +static int __init sky1_pinctrl_init(void) +{ + return platform_driver_register(&sky1_pinctrl_driver); +} +arch_initcall(sky1_pinctrl_init); + +MODULE_AUTHOR("Jerry Zhu <Jerry.Zhu@cixtech.com>"); +MODULE_DESCRIPTION("Cix Sky1 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/cix/pinctrl-sky1.h b/drivers/pinctrl/cix/pinctrl-sky1.h new file mode 100644 index 000000000000..a8b099852965 --- /dev/null +++ b/drivers/pinctrl/cix/pinctrl-sky1.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Author: Jerry Zhu <Jerry.Zhu@cixtech.com> + */ + +#ifndef __DRIVERS_PINCTRL_SKY1_H +#define __DRIVERS_PINCTRL_SKY1_H + +struct sky1_pinctrl_group { + const char *name; + unsigned long config; + unsigned int pin; +}; + +struct sky1_pin_desc { + const struct pinctrl_pin_desc pin; + const char * const *func_group; + unsigned int nfunc; +}; + +struct sky1_pinctrl_soc_info { + const struct sky1_pin_desc *pins; + unsigned int npins; +}; + +#define SKY_PINFUNCTION(_pin, _func) \ +((struct sky1_pin_desc) { \ + .pin = _pin, \ + .func_group = _func##_group, \ + .nfunc = ARRAY_SIZE(_func##_group), \ + }) +/** + * @dev: a pointer back to containing device + * @base: the offset to the controller in virtual memory + */ +struct sky1_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + void __iomem *base; + const struct sky1_pinctrl_soc_info *info; + struct sky1_pinctrl_group *groups; + const char **grp_names; +}; + +int sky1_base_pinctrl_probe(struct platform_device *pdev, + const struct sky1_pinctrl_soc_info *info); + +#endif /* __DRIVERS_PINCTRL_SKY1_H */ diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index c5dbf4e9db84..83254a95ef17 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -70,6 +70,7 @@ void pinctrl_provide_dummies(void) { pinctrl_dummy_state = true; } +EXPORT_SYMBOL_GPL(pinctrl_provide_dummies); const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev) { @@ -2416,7 +2417,7 @@ EXPORT_SYMBOL_GPL(devm_pinctrl_unregister); static int __init pinctrl_init(void) { - pr_info("initialized pinctrl subsystem\n"); + pr_debug("initialized pinctrl subsystem\n"); pinctrl_init_debugfs(); return 0; } diff --git a/drivers/pinctrl/intel/pinctrl-alderlake.c b/drivers/pinctrl/intel/pinctrl-alderlake.c index 108eac205aa9..7bf1d5c285a0 100644 --- a/drivers/pinctrl/intel/pinctrl-alderlake.c +++ b/drivers/pinctrl/intel/pinctrl-alderlake.c @@ -27,14 +27,6 @@ #define ADL_S_GPI_IS 0x200 #define ADL_S_GPI_IE 0x220 -#define ADL_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define ADL_N_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, ADL_N) @@ -316,28 +308,28 @@ static const struct pinctrl_pin_desc adln_pins[] = { }; static const struct intel_padgroup adln_community0_gpps[] = { - ADL_GPP(0, 0, 25, 0), /* GPP_B */ - ADL_GPP(1, 26, 41, 32), /* GPP_T */ - ADL_GPP(2, 42, 66, 64), /* GPP_A */ + INTEL_GPP(0, 0, 25, 0), /* GPP_B */ + INTEL_GPP(1, 26, 41, 32), /* GPP_T */ + INTEL_GPP(2, 42, 66, 64), /* GPP_A */ }; static const struct intel_padgroup adln_community1_gpps[] = { - ADL_GPP(0, 67, 74, 96), /* GPP_S */ - ADL_GPP(1, 75, 94, 128), /* GPP_I */ - ADL_GPP(2, 95, 118, 160), /* GPP_H */ - ADL_GPP(3, 119, 139, 192), /* GPP_D */ - ADL_GPP(4, 140, 168, 224), /* vGPIO */ + INTEL_GPP(0, 67, 74, 96), /* GPP_S */ + INTEL_GPP(1, 75, 94, 128), /* GPP_I */ + INTEL_GPP(2, 95, 118, 160), /* GPP_H */ + INTEL_GPP(3, 119, 139, 192), /* GPP_D */ + INTEL_GPP(4, 140, 168, 224), /* vGPIO */ }; static const struct intel_padgroup adln_community4_gpps[] = { - ADL_GPP(0, 169, 192, 256), /* GPP_C */ - ADL_GPP(1, 193, 217, 288), /* GPP_F */ - ADL_GPP(2, 218, 223, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ - ADL_GPP(3, 224, 248, 320), /* GPP_E */ + INTEL_GPP(0, 169, 192, 256), /* GPP_C */ + INTEL_GPP(1, 193, 217, 288), /* GPP_F */ + INTEL_GPP(2, 218, 223, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ + INTEL_GPP(3, 224, 248, 320), /* GPP_E */ }; static const struct intel_padgroup adln_community5_gpps[] = { - ADL_GPP(0, 249, 256, 352), /* GPP_R */ + INTEL_GPP(0, 249, 256, 352), /* GPP_R */ }; static const struct intel_community adln_communities[] = { @@ -680,35 +672,35 @@ static const struct pinctrl_pin_desc adls_pins[] = { }; static const struct intel_padgroup adls_community0_gpps[] = { - ADL_GPP(0, 0, 24, 0), /* GPP_I */ - ADL_GPP(1, 25, 47, 32), /* GPP_R */ - ADL_GPP(2, 48, 59, 64), /* GPP_J */ - ADL_GPP(3, 60, 86, 96), /* vGPIO */ - ADL_GPP(4, 87, 94, 128), /* vGPIO_0 */ + INTEL_GPP(0, 0, 24, 0), /* GPP_I */ + INTEL_GPP(1, 25, 47, 32), /* GPP_R */ + INTEL_GPP(2, 48, 59, 64), /* GPP_J */ + INTEL_GPP(3, 60, 86, 96), /* vGPIO */ + INTEL_GPP(4, 87, 94, 128), /* vGPIO_0 */ }; static const struct intel_padgroup adls_community1_gpps[] = { - ADL_GPP(0, 95, 118, 160), /* GPP_B */ - ADL_GPP(1, 119, 126, 192), /* GPP_G */ - ADL_GPP(2, 127, 150, 224), /* GPP_H */ + INTEL_GPP(0, 95, 118, 160), /* GPP_B */ + INTEL_GPP(1, 119, 126, 192), /* GPP_G */ + INTEL_GPP(2, 127, 150, 224), /* GPP_H */ }; static const struct intel_padgroup adls_community3_gpps[] = { - ADL_GPP(0, 151, 159, INTEL_GPIO_BASE_NOMAP), /* SPI0 */ - ADL_GPP(1, 160, 175, 256), /* GPP_A */ - ADL_GPP(2, 176, 199, 288), /* GPP_C */ + INTEL_GPP(0, 151, 159, INTEL_GPIO_BASE_NOMAP), /* SPI0 */ + INTEL_GPP(1, 160, 175, 256), /* GPP_A */ + INTEL_GPP(2, 176, 199, 288), /* GPP_C */ }; static const struct intel_padgroup adls_community4_gpps[] = { - ADL_GPP(0, 200, 207, 320), /* GPP_S */ - ADL_GPP(1, 208, 230, 352), /* GPP_E */ - ADL_GPP(2, 231, 245, 384), /* GPP_K */ - ADL_GPP(3, 246, 269, 416), /* GPP_F */ + INTEL_GPP(0, 200, 207, 320), /* GPP_S */ + INTEL_GPP(1, 208, 230, 352), /* GPP_E */ + INTEL_GPP(2, 231, 245, 384), /* GPP_K */ + INTEL_GPP(3, 246, 269, 416), /* GPP_F */ }; static const struct intel_padgroup adls_community5_gpps[] = { - ADL_GPP(0, 270, 294, 448), /* GPP_D */ - ADL_GPP(1, 295, 303, INTEL_GPIO_BASE_NOMAP), /* JTAG */ + INTEL_GPP(0, 270, 294, 448), /* GPP_D */ + INTEL_GPP(1, 295, 303, INTEL_GPIO_BASE_NOMAP), /* JTAG */ }; static const struct intel_community adls_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 5fd107a00ef8..b3a5222a175f 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1498,9 +1498,9 @@ static int byt_gpio_add_pin_ranges(struct gpio_chip *chip) ret = gpiochip_add_pin_range(chip, dev_name(dev), 0, 0, vg->soc->npins); if (ret) - dev_err(dev, "failed to add GPIO pin range\n"); + return dev_err_probe(dev, ret, "failed to add GPIO pin range\n"); - return ret; + return 0; } static int byt_gpio_probe(struct intel_pinctrl *vg) @@ -1548,9 +1548,9 @@ static int byt_gpio_probe(struct intel_pinctrl *vg) ret = devm_gpiochip_add_data(vg->dev, gc, vg); if (ret) - dev_err(vg->dev, "failed adding byt-gpio chip\n"); + return dev_err_probe(vg->dev, ret, "failed to register gpiochip\n"); - return ret; + return 0; } static int byt_set_soc_data(struct intel_pinctrl *vg, @@ -1601,10 +1601,8 @@ static int byt_pinctrl_probe(struct platform_device *pdev) vg->dev = dev; ret = byt_set_soc_data(vg, soc_data); - if (ret) { - dev_err(dev, "failed to set soc data\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to set soc data\n"); vg->pctldesc = byt_pinctrl_desc; vg->pctldesc.name = dev_name(dev); @@ -1612,10 +1610,8 @@ static int byt_pinctrl_probe(struct platform_device *pdev) vg->pctldesc.npins = vg->soc->npins; vg->pctldev = devm_pinctrl_register(dev, &vg->pctldesc, vg); - if (IS_ERR(vg->pctldev)) { - dev_err(dev, "failed to register pinctrl driver\n"); - return PTR_ERR(vg->pctldev); - } + if (IS_ERR(vg->pctldev)) + return dev_err_probe(dev, PTR_ERR(vg->pctldev), "failed to register pinctrl\n"); ret = byt_gpio_probe(vg); if (ret) diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c index 14a5d339385d..a3ffd19fd5be 100644 --- a/drivers/pinctrl/intel/pinctrl-cannonlake.c +++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c @@ -28,14 +28,6 @@ #define CNL_H_GPI_IS 0x100 #define CNL_H_GPI_IE 0x120 -#define CNL_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define CNL_LP_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, CNL_LP) @@ -362,32 +354,32 @@ static const struct pinctrl_pin_desc cnlh_pins[] = { }; static const struct intel_padgroup cnlh_community0_gpps[] = { - CNL_GPP(0, 0, 24, 0), /* GPP_A */ - CNL_GPP(1, 25, 50, 32), /* GPP_B */ + INTEL_GPP(0, 0, 24, 0), /* GPP_A */ + INTEL_GPP(1, 25, 50, 32), /* GPP_B */ }; static const struct intel_padgroup cnlh_community1_gpps[] = { - CNL_GPP(0, 51, 74, 64), /* GPP_C */ - CNL_GPP(1, 75, 98, 96), /* GPP_D */ - CNL_GPP(2, 99, 106, 128), /* GPP_G */ - CNL_GPP(3, 107, 114, INTEL_GPIO_BASE_NOMAP), /* AZA */ - CNL_GPP(4, 115, 146, 160), /* vGPIO_0 */ - CNL_GPP(5, 147, 154, INTEL_GPIO_BASE_NOMAP), /* vGPIO_1 */ + INTEL_GPP(0, 51, 74, 64), /* GPP_C */ + INTEL_GPP(1, 75, 98, 96), /* GPP_D */ + INTEL_GPP(2, 99, 106, 128), /* GPP_G */ + INTEL_GPP(3, 107, 114, INTEL_GPIO_BASE_NOMAP), /* AZA */ + INTEL_GPP(4, 115, 146, 160), /* vGPIO_0 */ + INTEL_GPP(5, 147, 154, INTEL_GPIO_BASE_NOMAP), /* vGPIO_1 */ }; static const struct intel_padgroup cnlh_community3_gpps[] = { - CNL_GPP(0, 155, 178, 192), /* GPP_K */ - CNL_GPP(1, 179, 202, 224), /* GPP_H */ - CNL_GPP(2, 203, 215, 256), /* GPP_E */ - CNL_GPP(3, 216, 239, 288), /* GPP_F */ - CNL_GPP(4, 240, 248, INTEL_GPIO_BASE_NOMAP), /* SPI */ + INTEL_GPP(0, 155, 178, 192), /* GPP_K */ + INTEL_GPP(1, 179, 202, 224), /* GPP_H */ + INTEL_GPP(2, 203, 215, 256), /* GPP_E */ + INTEL_GPP(3, 216, 239, 288), /* GPP_F */ + INTEL_GPP(4, 240, 248, INTEL_GPIO_BASE_NOMAP), /* SPI */ }; static const struct intel_padgroup cnlh_community4_gpps[] = { - CNL_GPP(0, 249, 259, INTEL_GPIO_BASE_NOMAP), /* CPU */ - CNL_GPP(1, 260, 268, INTEL_GPIO_BASE_NOMAP), /* JTAG */ - CNL_GPP(2, 269, 286, 320), /* GPP_I */ - CNL_GPP(3, 287, 298, 352), /* GPP_J */ + INTEL_GPP(0, 249, 259, INTEL_GPIO_BASE_NOMAP), /* CPU */ + INTEL_GPP(1, 260, 268, INTEL_GPIO_BASE_NOMAP), /* JTAG */ + INTEL_GPP(2, 269, 286, 320), /* GPP_I */ + INTEL_GPP(3, 287, 298, 352), /* GPP_J */ }; static const unsigned int cnlh_spi0_pins[] = { 40, 41, 42, 43 }; @@ -780,25 +772,25 @@ static const struct intel_function cnllp_functions[] = { }; static const struct intel_padgroup cnllp_community0_gpps[] = { - CNL_GPP(0, 0, 24, 0), /* GPP_A */ - CNL_GPP(1, 25, 50, 32), /* GPP_B */ - CNL_GPP(2, 51, 58, 64), /* GPP_G */ - CNL_GPP(3, 59, 67, INTEL_GPIO_BASE_NOMAP), /* SPI */ + INTEL_GPP(0, 0, 24, 0), /* GPP_A */ + INTEL_GPP(1, 25, 50, 32), /* GPP_B */ + INTEL_GPP(2, 51, 58, 64), /* GPP_G */ + INTEL_GPP(3, 59, 67, INTEL_GPIO_BASE_NOMAP), /* SPI */ }; static const struct intel_padgroup cnllp_community1_gpps[] = { - CNL_GPP(0, 68, 92, 96), /* GPP_D */ - CNL_GPP(1, 93, 116, 128), /* GPP_F */ - CNL_GPP(2, 117, 140, 160), /* GPP_H */ - CNL_GPP(3, 141, 172, 192), /* vGPIO */ - CNL_GPP(4, 173, 180, 224), /* vGPIO */ + INTEL_GPP(0, 68, 92, 96), /* GPP_D */ + INTEL_GPP(1, 93, 116, 128), /* GPP_F */ + INTEL_GPP(2, 117, 140, 160), /* GPP_H */ + INTEL_GPP(3, 141, 172, 192), /* vGPIO */ + INTEL_GPP(4, 173, 180, 224), /* vGPIO */ }; static const struct intel_padgroup cnllp_community4_gpps[] = { - CNL_GPP(0, 181, 204, 256), /* GPP_C */ - CNL_GPP(1, 205, 228, 288), /* GPP_E */ - CNL_GPP(2, 229, 237, INTEL_GPIO_BASE_NOMAP), /* JTAG */ - CNL_GPP(3, 238, 243, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ + INTEL_GPP(0, 181, 204, 256), /* GPP_C */ + INTEL_GPP(1, 205, 228, 288), /* GPP_E */ + INTEL_GPP(2, 229, 237, INTEL_GPIO_BASE_NOMAP), /* JTAG */ + INTEL_GPP(3, 238, 243, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ }; static const struct intel_community cnllp_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-cedarfork.c b/drivers/pinctrl/intel/pinctrl-cedarfork.c index 2ce97abeb0e4..2916f7d90090 100644 --- a/drivers/pinctrl/intel/pinctrl-cedarfork.c +++ b/drivers/pinctrl/intel/pinctrl-cedarfork.c @@ -21,13 +21,6 @@ #define CDF_GPI_IS 0x200 #define CDF_GPI_IE 0x230 -#define CDF_GPP(r, s, e) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - } - #define CDF_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, CDF) @@ -288,24 +281,24 @@ static const struct pinctrl_pin_desc cdf_pins[] = { }; static const struct intel_padgroup cdf_community0_gpps[] = { - CDF_GPP(0, 0, 23), /* WEST2 */ - CDF_GPP(1, 24, 47), /* WEST3 */ - CDF_GPP(2, 48, 70), /* WEST01 */ - CDF_GPP(3, 71, 90), /* WEST5 */ - CDF_GPP(4, 91, 96), /* WESTC */ - CDF_GPP(5, 97, 101), /* WESTC_DFX */ - CDF_GPP(6, 102, 111), /* WESTA */ - CDF_GPP(7, 112, 123), /* WESTB */ - CDF_GPP(8, 124, 143), /* WESTD */ - CDF_GPP(9, 144, 144), /* WESTD_PECI */ - CDF_GPP(10, 145, 167), /* WESTF */ + INTEL_GPP(0, 0, 23, 0), /* WEST2 */ + INTEL_GPP(1, 24, 47, 24), /* WEST3 */ + INTEL_GPP(2, 48, 70, 48), /* WEST01 */ + INTEL_GPP(3, 71, 90, 71), /* WEST5 */ + INTEL_GPP(4, 91, 96, 91), /* WESTC */ + INTEL_GPP(5, 97, 101, 97), /* WESTC_DFX */ + INTEL_GPP(6, 102, 111, 102), /* WESTA */ + INTEL_GPP(7, 112, 123, 112), /* WESTB */ + INTEL_GPP(8, 124, 143, 124), /* WESTD */ + INTEL_GPP(9, 144, 144, 144), /* WESTD_PECI */ + INTEL_GPP(10, 145, 167, 145), /* WESTF */ }; static const struct intel_padgroup cdf_community1_gpps[] = { - CDF_GPP(0, 168, 191), /* EAST2 */ - CDF_GPP(1, 192, 202), /* EAST3 */ - CDF_GPP(2, 203, 225), /* EAST0 */ - CDF_GPP(3, 226, 236), /* EMMC */ + INTEL_GPP(0, 168, 191, 168), /* EAST2 */ + INTEL_GPP(1, 192, 202, 192), /* EAST3 */ + INTEL_GPP(2, 203, 225, 203), /* EAST0 */ + INTEL_GPP(3, 226, 236, 226), /* EMMC */ }; static const struct intel_community cdf_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index f81f7929cd3b..8bd0c8512f78 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -92,12 +92,6 @@ struct intel_community_context { #define PINMODE(m, i) ((m) | ((i) * PINMODE_INVERT_OE)) -#define CHV_GPP(start, end) \ - { \ - .base = (start), \ - .size = (end) - (start) + 1, \ - } - #define CHV_COMMUNITY(g, i, a) \ { \ .gpps = (g), \ @@ -258,13 +252,13 @@ static const struct intel_function southwest_functions[] = { }; static const struct intel_padgroup southwest_gpps[] = { - CHV_GPP(0, 7), - CHV_GPP(15, 22), - CHV_GPP(30, 37), - CHV_GPP(45, 52), - CHV_GPP(60, 67), - CHV_GPP(75, 82), - CHV_GPP(90, 97), + INTEL_GPP(0, 0, 7, 0), + INTEL_GPP(1, 15, 22, 15), + INTEL_GPP(2, 30, 37, 30), + INTEL_GPP(3, 45, 52, 45), + INTEL_GPP(4, 60, 67, 60), + INTEL_GPP(5, 75, 82, 75), + INTEL_GPP(6, 90, 97, 90), }; /* @@ -354,11 +348,11 @@ static const struct pinctrl_pin_desc north_pins[] = { }; static const struct intel_padgroup north_gpps[] = { - CHV_GPP(0, 8), - CHV_GPP(15, 27), - CHV_GPP(30, 41), - CHV_GPP(45, 56), - CHV_GPP(60, 72), + INTEL_GPP(0, 0, 8, 0), + INTEL_GPP(1, 15, 27, 15), + INTEL_GPP(2, 30, 41, 30), + INTEL_GPP(3, 45, 56, 45), + INTEL_GPP(4, 60, 72, 60), }; /* @@ -406,8 +400,8 @@ static const struct pinctrl_pin_desc east_pins[] = { }; static const struct intel_padgroup east_gpps[] = { - CHV_GPP(0, 11), - CHV_GPP(15, 26), + INTEL_GPP(0, 0, 11, 0), + INTEL_GPP(1, 15, 26, 15), }; static const struct intel_community east_communities[] = { @@ -526,12 +520,12 @@ static const struct intel_function southeast_functions[] = { }; static const struct intel_padgroup southeast_gpps[] = { - CHV_GPP(0, 7), - CHV_GPP(15, 26), - CHV_GPP(30, 35), - CHV_GPP(45, 52), - CHV_GPP(60, 69), - CHV_GPP(75, 85), + INTEL_GPP(0, 0, 7, 0), + INTEL_GPP(1, 15, 26, 15), + INTEL_GPP(2, 30, 35, 30), + INTEL_GPP(3, 45, 52, 45), + INTEL_GPP(4, 60, 69, 60), + INTEL_GPP(5, 75, 85, 75), }; static const struct intel_community southeast_communities[] = { @@ -1517,26 +1511,6 @@ static int chv_gpio_irq_init_hw(struct gpio_chip *chip) return 0; } -static int chv_gpio_add_pin_ranges(struct gpio_chip *chip) -{ - struct intel_pinctrl *pctrl = gpiochip_get_data(chip); - struct device *dev = pctrl->dev; - const struct intel_community *community = &pctrl->communities[0]; - const struct intel_padgroup *gpp; - int ret, i; - - for (i = 0; i < community->ngpps; i++) { - gpp = &community->gpps[i]; - ret = gpiochip_add_pin_range(chip, dev_name(dev), gpp->base, gpp->base, gpp->size); - if (ret) { - dev_err(dev, "failed to add GPIO pin range\n"); - return ret; - } - } - - return 0; -} - static int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq) { const struct intel_community *community = &pctrl->communities[0]; @@ -1550,7 +1524,7 @@ static int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq) chip->ngpio = pctrl->soc->pins[pctrl->soc->npins - 1].number + 1; chip->label = dev_name(dev); - chip->add_pin_ranges = chv_gpio_add_pin_ranges; + chip->add_pin_ranges = intel_gpio_add_pin_ranges; chip->parent = dev; chip->base = -1; @@ -1567,17 +1541,13 @@ static int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq) chip->irq.init_valid_mask = chv_init_irq_valid_mask; } else { irq_base = devm_irq_alloc_descs(dev, -1, 0, pctrl->soc->npins, NUMA_NO_NODE); - if (irq_base < 0) { - dev_err(dev, "Failed to allocate IRQ numbers\n"); - return irq_base; - } + if (irq_base < 0) + return dev_err_probe(dev, irq_base, "failed to allocate IRQ numbers\n"); } ret = devm_gpiochip_add_data(dev, chip, pctrl); - if (ret) { - dev_err(dev, "Failed to register gpiochip\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to register gpiochip\n"); if (!need_valid_mask) { for (i = 0; i < community->ngpps; i++) { @@ -1673,10 +1643,8 @@ static int chv_pinctrl_probe(struct platform_device *pdev) pctrl->pctldesc.npins = pctrl->soc->npins; pctrl->pctldev = devm_pinctrl_register(dev, &pctrl->pctldesc, pctrl); - if (IS_ERR(pctrl->pctldev)) { - dev_err(dev, "failed to register pinctrl driver\n"); - return PTR_ERR(pctrl->pctldev); - } + if (IS_ERR(pctrl->pctldev)) + return dev_err_probe(dev, PTR_ERR(pctrl->pctldev), "failed to register pinctrl\n"); ret = chv_gpio_probe(pctrl, irq); if (ret) diff --git a/drivers/pinctrl/intel/pinctrl-denverton.c b/drivers/pinctrl/intel/pinctrl-denverton.c index fef44c663be6..f492f73ba246 100644 --- a/drivers/pinctrl/intel/pinctrl-denverton.c +++ b/drivers/pinctrl/intel/pinctrl-denverton.c @@ -21,13 +21,6 @@ #define DNV_GPI_IS 0x100 #define DNV_GPI_IE 0x120 -#define DNV_GPP(n, s, e) \ - { \ - .reg_num = (n), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - } - #define DNV_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, DNV) @@ -222,16 +215,16 @@ static const struct intel_function dnv_functions[] = { }; static const struct intel_padgroup dnv_north_gpps[] = { - DNV_GPP(0, 0, 31), /* North ALL_0 */ - DNV_GPP(1, 32, 40), /* North ALL_1 */ + INTEL_GPP(0, 0, 31, 0), /* North ALL_0 */ + INTEL_GPP(1, 32, 40, 32), /* North ALL_1 */ }; static const struct intel_padgroup dnv_south_gpps[] = { - DNV_GPP(0, 41, 58), /* South DFX */ - DNV_GPP(1, 59, 90), /* South GPP0_0 */ - DNV_GPP(2, 91, 111), /* South GPP0_1 */ - DNV_GPP(3, 112, 143), /* South GPP1_0 */ - DNV_GPP(4, 144, 153), /* South GPP1_1 */ + INTEL_GPP(0, 41, 58, 41), /* South DFX */ + INTEL_GPP(1, 59, 90, 59), /* South GPP0_0 */ + INTEL_GPP(2, 91, 111, 91), /* South GPP0_1 */ + INTEL_GPP(3, 112, 143, 112), /* South GPP1_0 */ + INTEL_GPP(4, 144, 153, 144), /* South GPP1_1 */ }; static const struct intel_community dnv_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-elkhartlake.c b/drivers/pinctrl/intel/pinctrl-elkhartlake.c index ab414e07555a..0e8742f31cd4 100644 --- a/drivers/pinctrl/intel/pinctrl-elkhartlake.c +++ b/drivers/pinctrl/intel/pinctrl-elkhartlake.c @@ -21,13 +21,6 @@ #define EHL_GPI_IS 0x100 #define EHL_GPI_IE 0x120 -#define EHL_GPP(r, s, e) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - } - #define EHL_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, EHL) @@ -106,9 +99,9 @@ static const struct pinctrl_pin_desc ehl_community0_pins[] = { }; static const struct intel_padgroup ehl_community0_gpps[] = { - EHL_GPP(0, 0, 25), /* GPP_B */ - EHL_GPP(1, 26, 41), /* GPP_T */ - EHL_GPP(2, 42, 66), /* GPP_G */ + INTEL_GPP(0, 0, 25, 0), /* GPP_B */ + INTEL_GPP(1, 26, 41, 26), /* GPP_T */ + INTEL_GPP(2, 42, 66, 42), /* GPP_G */ }; static const struct intel_community ehl_community0[] = { @@ -245,11 +238,11 @@ static const struct pinctrl_pin_desc ehl_community1_pins[] = { }; static const struct intel_padgroup ehl_community1_gpps[] = { - EHL_GPP(0, 0, 15), /* GPP_V */ - EHL_GPP(1, 16, 39), /* GPP_H */ - EHL_GPP(2, 40, 60), /* GPP_D */ - EHL_GPP(3, 61, 84), /* GPP_U */ - EHL_GPP(4, 85, 112), /* vGPIO */ + INTEL_GPP(0, 0, 15, 0), /* GPP_V */ + INTEL_GPP(1, 16, 39, 16), /* GPP_H */ + INTEL_GPP(2, 40, 60, 40), /* GPP_D */ + INTEL_GPP(3, 61, 84, 61), /* GPP_U */ + INTEL_GPP(4, 85, 112, 85), /* vGPIO */ }; static const struct intel_community ehl_community1[] = { @@ -286,7 +279,7 @@ static const struct pinctrl_pin_desc ehl_community2_pins[] = { }; static const struct intel_padgroup ehl_community2_gpps[] = { - EHL_GPP(0, 0, 16), /* DSW */ + INTEL_GPP(0, 0, 16, 0), /* DSW */ }; static const struct intel_community ehl_community2[] = { @@ -356,10 +349,10 @@ static const struct pinctrl_pin_desc ehl_community3_pins[] = { }; static const struct intel_padgroup ehl_community3_gpps[] = { - EHL_GPP(0, 0, 16), /* CPU */ - EHL_GPP(1, 17, 18), /* GPP_S */ - EHL_GPP(2, 19, 42), /* GPP_A */ - EHL_GPP(3, 43, 46), /* vGPIO_3 */ + INTEL_GPP(0, 0, 16, 0), /* CPU */ + INTEL_GPP(1, 17, 18, 17), /* GPP_S */ + INTEL_GPP(2, 19, 42, 19), /* GPP_A */ + INTEL_GPP(3, 43, 46, 43), /* vGPIO_3 */ }; static const struct intel_community ehl_community3[] = { @@ -462,10 +455,10 @@ static const struct pinctrl_pin_desc ehl_community4_pins[] = { }; static const struct intel_padgroup ehl_community4_gpps[] = { - EHL_GPP(0, 0, 23), /* GPP_C */ - EHL_GPP(1, 24, 48), /* GPP_F */ - EHL_GPP(2, 49, 54), /* HVCMOS */ - EHL_GPP(3, 55, 79), /* GPP_E */ + INTEL_GPP(0, 0, 23, 0), /* GPP_C */ + INTEL_GPP(1, 24, 48, 24), /* GPP_F */ + INTEL_GPP(2, 49, 54, 49), /* HVCMOS */ + INTEL_GPP(3, 55, 79, 55), /* GPP_E */ }; static const struct intel_community ehl_community4[] = { @@ -493,7 +486,7 @@ static const struct pinctrl_pin_desc ehl_community5_pins[] = { }; static const struct intel_padgroup ehl_community5_gpps[] = { - EHL_GPP(0, 0, 7), /* GPP_R */ + INTEL_GPP(0, 0, 7, 0), /* GPP_R */ }; static const struct intel_community ehl_community5[] = { diff --git a/drivers/pinctrl/intel/pinctrl-emmitsburg.c b/drivers/pinctrl/intel/pinctrl-emmitsburg.c index 9d8a32aca177..ba06a9ec239a 100644 --- a/drivers/pinctrl/intel/pinctrl-emmitsburg.c +++ b/drivers/pinctrl/intel/pinctrl-emmitsburg.c @@ -21,13 +21,6 @@ #define EBG_GPI_IS 0x200 #define EBG_GPI_IE 0x210 -#define EBG_GPP(r, s, e) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - } - #define EBG_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, EBG) @@ -311,31 +304,31 @@ static const struct pinctrl_pin_desc ebg_pins[] = { }; static const struct intel_padgroup ebg_community0_gpps[] = { - EBG_GPP(0, 0, 20), /* GPP_A */ - EBG_GPP(1, 21, 44), /* GPP_B */ - EBG_GPP(2, 45, 65), /* SPI */ + INTEL_GPP(0, 0, 20, 0), /* GPP_A */ + INTEL_GPP(1, 21, 44, 21), /* GPP_B */ + INTEL_GPP(2, 45, 65, 45), /* SPI */ }; static const struct intel_padgroup ebg_community1_gpps[] = { - EBG_GPP(0, 66, 87), /* GPP_C */ - EBG_GPP(1, 88, 111), /* GPP_D */ + INTEL_GPP(0, 66, 87, 66), /* GPP_C */ + INTEL_GPP(1, 88, 111, 88), /* GPP_D */ }; static const struct intel_padgroup ebg_community3_gpps[] = { - EBG_GPP(0, 112, 135), /* GPP_E */ - EBG_GPP(1, 136, 145), /* JTAG */ + INTEL_GPP(0, 112, 135, 112), /* GPP_E */ + INTEL_GPP(1, 136, 145, 136), /* JTAG */ }; static const struct intel_padgroup ebg_community4_gpps[] = { - EBG_GPP(0, 146, 165), /* GPP_H */ - EBG_GPP(1, 166, 183), /* GPP_J */ + INTEL_GPP(0, 146, 165, 146), /* GPP_H */ + INTEL_GPP(1, 166, 183, 166), /* GPP_J */ }; static const struct intel_padgroup ebg_community5_gpps[] = { - EBG_GPP(0, 184, 207), /* GPP_I */ - EBG_GPP(1, 208, 225), /* GPP_L */ - EBG_GPP(2, 226, 243), /* GPP_M */ - EBG_GPP(3, 244, 261), /* GPP_N */ + INTEL_GPP(0, 184, 207, 184), /* GPP_I */ + INTEL_GPP(1, 208, 225, 208), /* GPP_L */ + INTEL_GPP(2, 226, 243, 226), /* GPP_M */ + INTEL_GPP(3, 244, 261, 244), /* GPP_N */ }; static const struct intel_community ebg_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-icelake.c b/drivers/pinctrl/intel/pinctrl-icelake.c index 7e028c61ed0f..1516fe7b4e4a 100644 --- a/drivers/pinctrl/intel/pinctrl-icelake.c +++ b/drivers/pinctrl/intel/pinctrl-icelake.c @@ -28,14 +28,6 @@ #define ICL_N_GPI_IS 0x100 #define ICL_N_GPI_IE 0x120 -#define ICL_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define ICL_LP_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, ICL_LP) @@ -302,29 +294,29 @@ static const struct pinctrl_pin_desc icllp_pins[] = { }; static const struct intel_padgroup icllp_community0_gpps[] = { - ICL_GPP(0, 0, 7, 0), /* GPP_G */ - ICL_GPP(1, 8, 33, 32), /* GPP_B */ - ICL_GPP(2, 34, 58, 64), /* GPP_A */ + INTEL_GPP(0, 0, 7, 0), /* GPP_G */ + INTEL_GPP(1, 8, 33, 32), /* GPP_B */ + INTEL_GPP(2, 34, 58, 64), /* GPP_A */ }; static const struct intel_padgroup icllp_community1_gpps[] = { - ICL_GPP(0, 59, 82, 96), /* GPP_H */ - ICL_GPP(1, 83, 103, 128), /* GPP_D */ - ICL_GPP(2, 104, 123, 160), /* GPP_F */ - ICL_GPP(3, 124, 152, 192), /* vGPIO */ + INTEL_GPP(0, 59, 82, 96), /* GPP_H */ + INTEL_GPP(1, 83, 103, 128), /* GPP_D */ + INTEL_GPP(2, 104, 123, 160), /* GPP_F */ + INTEL_GPP(3, 124, 152, 192), /* vGPIO */ }; static const struct intel_padgroup icllp_community4_gpps[] = { - ICL_GPP(0, 153, 176, 224), /* GPP_C */ - ICL_GPP(1, 177, 182, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ - ICL_GPP(2, 183, 206, 256), /* GPP_E */ - ICL_GPP(3, 207, 215, INTEL_GPIO_BASE_NOMAP), /* JTAG */ + INTEL_GPP(0, 153, 176, 224), /* GPP_C */ + INTEL_GPP(1, 177, 182, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ + INTEL_GPP(2, 183, 206, 256), /* GPP_E */ + INTEL_GPP(3, 207, 215, INTEL_GPIO_BASE_NOMAP), /* JTAG */ }; static const struct intel_padgroup icllp_community5_gpps[] = { - ICL_GPP(0, 216, 223, 288), /* GPP_R */ - ICL_GPP(1, 224, 231, 320), /* GPP_S */ - ICL_GPP(2, 232, 240, INTEL_GPIO_BASE_NOMAP), /* SPI */ + INTEL_GPP(0, 216, 223, 288), /* GPP_R */ + INTEL_GPP(1, 224, 231, 320), /* GPP_S */ + INTEL_GPP(2, 232, 240, INTEL_GPIO_BASE_NOMAP), /* SPI */ }; static const struct intel_community icllp_communities[] = { @@ -632,27 +624,27 @@ static const struct pinctrl_pin_desc icln_pins[] = { }; static const struct intel_padgroup icln_community0_gpps[] = { - ICL_GPP(0, 0, 8, INTEL_GPIO_BASE_NOMAP), /* SPI */ - ICL_GPP(1, 9, 34, 32), /* GPP_B */ - ICL_GPP(2, 35, 55, 64), /* GPP_A */ - ICL_GPP(3, 56, 63, 96), /* GPP_S */ - ICL_GPP(4, 64, 71, 128), /* GPP_R */ + INTEL_GPP(0, 0, 8, INTEL_GPIO_BASE_NOMAP), /* SPI */ + INTEL_GPP(1, 9, 34, 32), /* GPP_B */ + INTEL_GPP(2, 35, 55, 64), /* GPP_A */ + INTEL_GPP(3, 56, 63, 96), /* GPP_S */ + INTEL_GPP(4, 64, 71, 128), /* GPP_R */ }; static const struct intel_padgroup icln_community1_gpps[] = { - ICL_GPP(0, 72, 95, 160), /* GPP_H */ - ICL_GPP(1, 96, 121, 192), /* GPP_D */ - ICL_GPP(2, 122, 150, 224), /* vGPIO */ - ICL_GPP(3, 151, 174, 256), /* GPP_C */ + INTEL_GPP(0, 72, 95, 160), /* GPP_H */ + INTEL_GPP(1, 96, 121, 192), /* GPP_D */ + INTEL_GPP(2, 122, 150, 224), /* vGPIO */ + INTEL_GPP(3, 151, 174, 256), /* GPP_C */ }; static const struct intel_padgroup icln_community4_gpps[] = { - ICL_GPP(0, 175, 180, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ - ICL_GPP(1, 181, 204, 288), /* GPP_E */ + INTEL_GPP(0, 175, 180, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ + INTEL_GPP(1, 181, 204, 288), /* GPP_E */ }; static const struct intel_padgroup icln_community5_gpps[] = { - ICL_GPP(0, 205, 212, INTEL_GPIO_BASE_ZERO), /* GPP_G */ + INTEL_GPP(0, 205, 212, INTEL_GPIO_BASE_ZERO), /* GPP_G */ }; static const struct intel_community icln_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index d68cef4ec52a..cf9db8ac0f42 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1345,7 +1345,16 @@ static int intel_gpio_irq_init_hw(struct gpio_chip *gc) return 0; } -static int intel_gpio_add_pin_ranges(struct gpio_chip *gc) +/** + * intel_gpio_add_pin_ranges - add GPIO pin ranges for all groups in all communities + * @gc: GPIO chip structure + * + * This function iterates over all communities and all groups and adds the respective + * GPIO pin ranges, so the GPIO library will correctly map a GPIO offset to a pin number. + * + * Return: 0, or negative error code if range can't be added. + */ +int intel_gpio_add_pin_ranges(struct gpio_chip *gc) { struct intel_pinctrl *pctrl = gpiochip_get_data(gc); const struct intel_community *community; @@ -1356,14 +1365,13 @@ static int intel_gpio_add_pin_ranges(struct gpio_chip *gc) ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), grp->gpio_base, grp->base, grp->size); - if (ret) { - dev_err(pctrl->dev, "failed to add GPIO pin range\n"); - return ret; - } + if (ret) + return dev_err_probe(pctrl->dev, ret, "failed to add GPIO pin range\n"); } return 0; } +EXPORT_SYMBOL_NS_GPL(intel_gpio_add_pin_ranges, "PINCTRL_INTEL"); static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl) { @@ -1401,10 +1409,8 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq, IRQF_SHARED | IRQF_NO_THREAD, dev_name(pctrl->dev), pctrl); - if (ret) { - dev_err(pctrl->dev, "failed to request interrupt\n"); - return ret; - } + if (ret) + return dev_err_probe(pctrl->dev, ret, "failed to request interrupt\n"); /* Setup IRQ chip */ girq = &pctrl->chip.irq; @@ -1417,10 +1423,8 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) girq->init_hw = intel_gpio_irq_init_hw; ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); - if (ret) { - dev_err(pctrl->dev, "failed to register gpiochip\n"); - return ret; - } + if (ret) + return dev_err_probe(pctrl->dev, ret, "failed to register gpiochip\n"); return 0; } @@ -1668,10 +1672,8 @@ int intel_pinctrl_probe(struct platform_device *pdev, pctrl->pctldesc.npins = pctrl->soc->npins; pctrl->pctldev = devm_pinctrl_register(dev, &pctrl->pctldesc, pctrl); - if (IS_ERR(pctrl->pctldev)) { - dev_err(dev, "failed to register pinctrl driver\n"); - return PTR_ERR(pctrl->pctldev); - } + if (IS_ERR(pctrl->pctldev)) + return dev_err_probe(dev, PTR_ERR(pctrl->pctldev), "failed to register pinctrl\n"); ret = intel_gpio_probe(pctrl, irq); if (ret) diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h index 4d4e1257afdf..c1520797f895 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.h +++ b/drivers/pinctrl/intel/pinctrl-intel.h @@ -76,6 +76,15 @@ enum { INTEL_GPIO_BASE_MATCH = 0, }; +/* Initialise struct intel_padgroup */ +#define INTEL_GPP(r, s, e, g) \ + { \ + .reg_num = (r), \ + .base = (s), \ + .size = ((e) - (s) + 1), \ + .gpio_base = (g), \ + } + /** * struct intel_community - Intel pin community description * @barno: MMIO BAR number where registers for this community reside @@ -267,6 +276,8 @@ extern const struct dev_pm_ops intel_pinctrl_pm_ops; const struct intel_community *intel_get_community(const struct intel_pinctrl *pctrl, unsigned int pin); +int intel_gpio_add_pin_ranges(struct gpio_chip *gc); + int intel_get_groups_count(struct pinctrl_dev *pctldev); const char *intel_get_group_name(struct pinctrl_dev *pctldev, unsigned int group); int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, diff --git a/drivers/pinctrl/intel/pinctrl-jasperlake.c b/drivers/pinctrl/intel/pinctrl-jasperlake.c index aef0e7f92154..c6e1836c69a7 100644 --- a/drivers/pinctrl/intel/pinctrl-jasperlake.c +++ b/drivers/pinctrl/intel/pinctrl-jasperlake.c @@ -21,14 +21,6 @@ #define JSL_GPI_IS 0x100 #define JSL_GPI_IE 0x120 -#define JSL_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define JSL_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, JSL) @@ -283,28 +275,28 @@ static const struct pinctrl_pin_desc jsl_pins[] = { }; static const struct intel_padgroup jsl_community0_gpps[] = { - JSL_GPP(0, 0, 19, 320), /* GPP_F */ - JSL_GPP(1, 20, 28, INTEL_GPIO_BASE_NOMAP), /* SPI */ - JSL_GPP(2, 29, 54, 32), /* GPP_B */ - JSL_GPP(3, 55, 75, 64), /* GPP_A */ - JSL_GPP(4, 76, 83, 96), /* GPP_S */ - JSL_GPP(5, 84, 91, 128), /* GPP_R */ + INTEL_GPP(0, 0, 19, 320), /* GPP_F */ + INTEL_GPP(1, 20, 28, INTEL_GPIO_BASE_NOMAP), /* SPI */ + INTEL_GPP(2, 29, 54, 32), /* GPP_B */ + INTEL_GPP(3, 55, 75, 64), /* GPP_A */ + INTEL_GPP(4, 76, 83, 96), /* GPP_S */ + INTEL_GPP(5, 84, 91, 128), /* GPP_R */ }; static const struct intel_padgroup jsl_community1_gpps[] = { - JSL_GPP(0, 92, 115, 160), /* GPP_H */ - JSL_GPP(1, 116, 141, 192), /* GPP_D */ - JSL_GPP(2, 142, 170, 224), /* vGPIO */ - JSL_GPP(3, 171, 194, 256), /* GPP_C */ + INTEL_GPP(0, 92, 115, 160), /* GPP_H */ + INTEL_GPP(1, 116, 141, 192), /* GPP_D */ + INTEL_GPP(2, 142, 170, 224), /* vGPIO */ + INTEL_GPP(3, 171, 194, 256), /* GPP_C */ }; static const struct intel_padgroup jsl_community4_gpps[] = { - JSL_GPP(0, 195, 200, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ - JSL_GPP(1, 201, 224, 288), /* GPP_E */ + INTEL_GPP(0, 195, 200, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ + INTEL_GPP(1, 201, 224, 288), /* GPP_E */ }; static const struct intel_padgroup jsl_community5_gpps[] = { - JSL_GPP(0, 225, 232, INTEL_GPIO_BASE_ZERO), /* GPP_G */ + INTEL_GPP(0, 225, 232, INTEL_GPIO_BASE_ZERO), /* GPP_G */ }; static const struct intel_community jsl_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-lakefield.c b/drivers/pinctrl/intel/pinctrl-lakefield.c index 60281f421608..bfb8b565d15c 100644 --- a/drivers/pinctrl/intel/pinctrl-lakefield.c +++ b/drivers/pinctrl/intel/pinctrl-lakefield.c @@ -21,14 +21,6 @@ #define LKF_GPI_IS 0x100 #define LKF_GPI_IE 0x110 -#define LKF_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define LKF_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, LKF) @@ -308,24 +300,24 @@ static const struct pinctrl_pin_desc lkf_pins[] = { }; static const struct intel_padgroup lkf_community0_gpps[] = { - LKF_GPP(0, 0, 31, 0), /* EAST_0 */ - LKF_GPP(1, 32, 59, 32), /* EAST_1 */ + INTEL_GPP(0, 0, 31, 0), /* EAST_0 */ + INTEL_GPP(1, 32, 59, 32), /* EAST_1 */ }; static const struct intel_padgroup lkf_community1_gpps[] = { - LKF_GPP(0, 60, 91, 64), /* NORTHWEST_0 */ - LKF_GPP(1, 92, 123, 96), /* NORTHWEST_1 */ - LKF_GPP(2, 124, 148, 128), /* NORTHWEST_2 */ + INTEL_GPP(0, 60, 91, 64), /* NORTHWEST_0 */ + INTEL_GPP(1, 92, 123, 96), /* NORTHWEST_1 */ + INTEL_GPP(2, 124, 148, 128), /* NORTHWEST_2 */ }; static const struct intel_padgroup lkf_community2_gpps[] = { - LKF_GPP(0, 149, 180, 160), /* WEST_0 */ - LKF_GPP(1, 181, 212, 192), /* WEST_1 */ - LKF_GPP(2, 213, 237, 224), /* WEST_2 */ + INTEL_GPP(0, 149, 180, 160), /* WEST_0 */ + INTEL_GPP(1, 181, 212, 192), /* WEST_1 */ + INTEL_GPP(2, 213, 237, 224), /* WEST_2 */ }; static const struct intel_padgroup lkf_community3_gpps[] = { - LKF_GPP(0, 238, 266, 256), /* SOUTHEAST */ + INTEL_GPP(0, 238, 266, 256), /* SOUTHEAST */ }; static const struct intel_community lkf_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c index 3fb628309fb2..1565eefdd4bf 100644 --- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c +++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c @@ -700,9 +700,9 @@ static int lp_gpio_add_pin_ranges(struct gpio_chip *chip) ret = gpiochip_add_pin_range(chip, dev_name(dev), 0, 0, lg->soc->npins); if (ret) - dev_err(dev, "failed to add GPIO pin range\n"); + return dev_err_probe(dev, ret, "failed to add GPIO pin range\n"); - return ret; + return 0; } static int lp_gpio_probe(struct platform_device *pdev) @@ -739,24 +739,18 @@ static int lp_gpio_probe(struct platform_device *pdev) lg->pctldesc.npins = lg->soc->npins; lg->pctldev = devm_pinctrl_register(dev, &lg->pctldesc, lg); - if (IS_ERR(lg->pctldev)) { - dev_err(dev, "failed to register pinctrl driver\n"); - return PTR_ERR(lg->pctldev); - } + if (IS_ERR(lg->pctldev)) + return dev_err_probe(dev, PTR_ERR(lg->pctldev), "failed to register pinctrl\n"); platform_set_drvdata(pdev, lg); io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!io_rc) { - dev_err(dev, "missing IO resources\n"); - return -EINVAL; - } + if (!io_rc) + return dev_err_probe(dev, -EINVAL, "missing IO resources\n"); regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc)); - if (!regs) { - dev_err(dev, "failed mapping IO region %pR\n", &io_rc); - return -EBUSY; - } + if (!regs) + return dev_err_probe(dev, -EBUSY, "failed mapping IO region %pR\n", &io_rc); for (i = 0; i < lg->soc->ncommunities; i++) { struct intel_community *comm = &lg->communities[i]; @@ -807,10 +801,8 @@ static int lp_gpio_probe(struct platform_device *pdev) } ret = devm_gpiochip_add_data(dev, gc, lg); - if (ret) { - dev_err(dev, "failed adding lp-gpio chip\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to register gpiochip\n"); return 0; } diff --git a/drivers/pinctrl/intel/pinctrl-meteorlake.c b/drivers/pinctrl/intel/pinctrl-meteorlake.c index f564376ce437..b7395947569a 100644 --- a/drivers/pinctrl/intel/pinctrl-meteorlake.c +++ b/drivers/pinctrl/intel/pinctrl-meteorlake.c @@ -27,14 +27,6 @@ #define MTL_S_GPI_IS 0x200 #define MTL_S_GPI_IE 0x210 -#define MTL_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define MTL_P_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, MTL_P) @@ -349,33 +341,33 @@ static const struct pinctrl_pin_desc mtlp_pins[] = { }; static const struct intel_padgroup mtlp_community0_gpps[] = { - MTL_GPP(0, 0, 4, 0), /* CPU */ - MTL_GPP(1, 5, 28, 32), /* GPP_V */ - MTL_GPP(2, 29, 52, 64), /* GPP_C */ + INTEL_GPP(0, 0, 4, 0), /* CPU */ + INTEL_GPP(1, 5, 28, 32), /* GPP_V */ + INTEL_GPP(2, 29, 52, 64), /* GPP_C */ }; static const struct intel_padgroup mtlp_community1_gpps[] = { - MTL_GPP(0, 53, 77, 96), /* GPP_A */ - MTL_GPP(1, 78, 102, 128), /* GPP_E */ + INTEL_GPP(0, 53, 77, 96), /* GPP_A */ + INTEL_GPP(1, 78, 102, 128), /* GPP_E */ }; static const struct intel_padgroup mtlp_community3_gpps[] = { - MTL_GPP(0, 103, 128, 160), /* GPP_H */ - MTL_GPP(1, 129, 154, 192), /* GPP_F */ - MTL_GPP(2, 155, 169, 224), /* SPI0 */ - MTL_GPP(3, 170, 183, 256), /* vGPIO_3 */ + INTEL_GPP(0, 103, 128, 160), /* GPP_H */ + INTEL_GPP(1, 129, 154, 192), /* GPP_F */ + INTEL_GPP(2, 155, 169, 224), /* SPI0 */ + INTEL_GPP(3, 170, 183, 256), /* vGPIO_3 */ }; static const struct intel_padgroup mtlp_community4_gpps[] = { - MTL_GPP(0, 184, 191, 288), /* GPP_S */ - MTL_GPP(1, 192, 203, 320), /* JTAG */ + INTEL_GPP(0, 184, 191, 288), /* GPP_S */ + INTEL_GPP(1, 192, 203, 320), /* JTAG */ }; static const struct intel_padgroup mtlp_community5_gpps[] = { - MTL_GPP(0, 204, 228, 352), /* GPP_B */ - MTL_GPP(1, 229, 253, 384), /* GPP_D */ - MTL_GPP(2, 254, 285, 416), /* vGPIO_0 */ - MTL_GPP(3, 286, 288, 448), /* vGPIO_1 */ + INTEL_GPP(0, 204, 228, 352), /* GPP_B */ + INTEL_GPP(1, 229, 253, 384), /* GPP_D */ + INTEL_GPP(2, 254, 285, 416), /* vGPIO_0 */ + INTEL_GPP(3, 286, 288, 448), /* vGPIO_1 */ }; static const struct intel_community mtlp_communities[] = { @@ -554,20 +546,20 @@ static const struct pinctrl_pin_desc mtls_pins[] = { }; static const struct intel_padgroup mtls_community0_gpps[] = { - MTL_GPP(0, 0, 27, 0), /* GPP_A */ - MTL_GPP(1, 28, 46, 32), /* vGPIO_0 */ - MTL_GPP(2, 47, 73, 64), /* GPP_C */ + INTEL_GPP(0, 0, 27, 0), /* GPP_A */ + INTEL_GPP(1, 28, 46, 32), /* vGPIO_0 */ + INTEL_GPP(2, 47, 73, 64), /* GPP_C */ }; static const struct intel_padgroup mtls_community1_gpps[] = { - MTL_GPP(0, 74, 93, 96), /* GPP_B */ - MTL_GPP(1, 94, 95, 128), /* vGPIO_3 */ - MTL_GPP(2, 96, 119, 160), /* GPP_D */ + INTEL_GPP(0, 74, 93, 96), /* GPP_B */ + INTEL_GPP(1, 94, 95, 128), /* vGPIO_3 */ + INTEL_GPP(2, 96, 119, 160), /* GPP_D */ }; static const struct intel_padgroup mtls_community3_gpps[] = { - MTL_GPP(0, 120, 135, 192), /* JTAG_CPU */ - MTL_GPP(1, 136, 147, 224), /* vGPIO_4 */ + INTEL_GPP(0, 120, 135, 192), /* JTAG_CPU */ + INTEL_GPP(1, 136, 147, 224), /* vGPIO_4 */ }; static const struct intel_community mtls_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-meteorpoint.c b/drivers/pinctrl/intel/pinctrl-meteorpoint.c index ab46ac5f3b15..b7858c2b2c5c 100644 --- a/drivers/pinctrl/intel/pinctrl-meteorpoint.c +++ b/drivers/pinctrl/intel/pinctrl-meteorpoint.c @@ -21,14 +21,6 @@ #define MTP_GPI_IS 0x200 #define MTP_GPI_IE 0x220 -#define MTP_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define MTP_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, MTP) @@ -395,37 +387,37 @@ static const struct pinctrl_pin_desc mtps_pins[] = { }; static const struct intel_padgroup mtps_community0_gpps[] = { - MTP_GPP(0, 0, 24, 0), /* GPP_D */ - MTP_GPP(1, 25, 38, 32), /* GPP_R */ - MTP_GPP(2, 39, 56, 64), /* GPP_J */ - MTP_GPP(3, 57, 87, 96), /* vGPIO */ + INTEL_GPP(0, 0, 24, 0), /* GPP_D */ + INTEL_GPP(1, 25, 38, 32), /* GPP_R */ + INTEL_GPP(2, 39, 56, 64), /* GPP_J */ + INTEL_GPP(3, 57, 87, 96), /* vGPIO */ }; static const struct intel_padgroup mtps_community1_gpps[] = { - MTP_GPP(0, 88, 102, 128), /* GPP_A */ - MTP_GPP(1, 103, 114, 160), /* DIR_ESPI */ - MTP_GPP(2, 115, 136, 192), /* GPP_B */ + INTEL_GPP(0, 88, 102, 128), /* GPP_A */ + INTEL_GPP(1, 103, 114, 160), /* DIR_ESPI */ + INTEL_GPP(2, 115, 136, 192), /* GPP_B */ }; static const struct intel_padgroup mtps_community3_gpps[] = { - MTP_GPP(0, 137, 145, 224), /* SPI0 */ - MTP_GPP(1, 146, 169, 256), /* GPP_C */ - MTP_GPP(2, 170, 189, 288), /* GPP_H */ - MTP_GPP(3, 190, 193, 320), /* vGPIO_3 */ - MTP_GPP(4, 194, 201, 352), /* vGPIO_0 */ - MTP_GPP(5, 202, 232, 384), /* vGPIO_4 */ + INTEL_GPP(0, 137, 145, 224), /* SPI0 */ + INTEL_GPP(1, 146, 169, 256), /* GPP_C */ + INTEL_GPP(2, 170, 189, 288), /* GPP_H */ + INTEL_GPP(3, 190, 193, 320), /* vGPIO_3 */ + INTEL_GPP(4, 194, 201, 352), /* vGPIO_0 */ + INTEL_GPP(5, 202, 232, 384), /* vGPIO_4 */ }; static const struct intel_padgroup mtps_community4_gpps[] = { - MTP_GPP(0, 233, 240, 416), /* GPP_S */ - MTP_GPP(1, 241, 263, 448), /* GPP_E */ - MTP_GPP(2, 264, 277, 480), /* GPP_K */ - MTP_GPP(3, 278, 301, 512), /* GPP_F */ + INTEL_GPP(0, 233, 240, 416), /* GPP_S */ + INTEL_GPP(1, 241, 263, 448), /* GPP_E */ + INTEL_GPP(2, 264, 277, 480), /* GPP_K */ + INTEL_GPP(3, 278, 301, 512), /* GPP_F */ }; static const struct intel_padgroup mtps_community5_gpps[] = { - MTP_GPP(0, 302, 322, 544), /* GPP_I */ - MTP_GPP(1, 323, 338, 576), /* JTAG_CPU */ + INTEL_GPP(0, 302, 322, 544), /* GPP_I */ + INTEL_GPP(1, 323, 338, 576), /* JTAG_CPU */ }; static const struct intel_community mtps_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c index a7a5fa65fd9d..b51befde9e8b 100644 --- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c +++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c @@ -28,14 +28,6 @@ #define SPT_LP_GPI_IS 0x100 #define SPT_LP_GPI_IE 0x120 -#define SPT_H_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define SPT_H_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, SPT_H) @@ -538,21 +530,21 @@ static const struct intel_function spth_functions[] = { }; static const struct intel_padgroup spth_community0_gpps[] = { - SPT_H_GPP(0, 0, 23, 0), /* GPP_A */ - SPT_H_GPP(1, 24, 47, 24), /* GPP_B */ + INTEL_GPP(0, 0, 23, 0), /* GPP_A */ + INTEL_GPP(1, 24, 47, 24), /* GPP_B */ }; static const struct intel_padgroup spth_community1_gpps[] = { - SPT_H_GPP(0, 48, 71, 48), /* GPP_C */ - SPT_H_GPP(1, 72, 95, 72), /* GPP_D */ - SPT_H_GPP(2, 96, 108, 96), /* GPP_E */ - SPT_H_GPP(3, 109, 132, 120), /* GPP_F */ - SPT_H_GPP(4, 133, 156, 144), /* GPP_G */ - SPT_H_GPP(5, 157, 180, 168), /* GPP_H */ + INTEL_GPP(0, 48, 71, 48), /* GPP_C */ + INTEL_GPP(1, 72, 95, 72), /* GPP_D */ + INTEL_GPP(2, 96, 108, 96), /* GPP_E */ + INTEL_GPP(3, 109, 132, 120), /* GPP_F */ + INTEL_GPP(4, 133, 156, 144), /* GPP_G */ + INTEL_GPP(5, 157, 180, 168), /* GPP_H */ }; static const struct intel_padgroup spth_community3_gpps[] = { - SPT_H_GPP(0, 181, 191, 192), /* GPP_I */ + INTEL_GPP(0, 181, 191, 192), /* GPP_I */ }; static const struct intel_community spth_communities[] = { diff --git a/drivers/pinctrl/intel/pinctrl-tangier.c b/drivers/pinctrl/intel/pinctrl-tangier.c index ac61e632b487..5f0b7334a489 100644 --- a/drivers/pinctrl/intel/pinctrl-tangier.c +++ b/drivers/pinctrl/intel/pinctrl-tangier.c @@ -562,8 +562,7 @@ static int tng_pinctrl_probe(struct platform_device *pdev, tp->pctldev = devm_pinctrl_register(dev, &tp->pctldesc, tp); if (IS_ERR(tp->pctldev)) - return dev_err_probe(dev, PTR_ERR(tp->pctldev), - "failed to register pinctrl driver\n"); + return dev_err_probe(dev, PTR_ERR(tp->pctldev), "failed to register pinctrl\n"); return 0; } diff --git a/drivers/pinctrl/intel/pinctrl-tigerlake.c b/drivers/pinctrl/intel/pinctrl-tigerlake.c index c43576e10273..c0887596d113 100644 --- a/drivers/pinctrl/intel/pinctrl-tigerlake.c +++ b/drivers/pinctrl/intel/pinctrl-tigerlake.c @@ -28,14 +28,6 @@ #define TGL_H_GPI_IS 0x100 #define TGL_H_GPI_IE 0x120 -#define TGL_GPP(r, s, e, g) \ - { \ - .reg_num = (r), \ - .base = (s), \ - .size = ((e) - (s) + 1), \ - .gpio_base = (g), \ - } - #define TGL_LP_COMMUNITY(b, s, e, g) \ INTEL_COMMUNITY_GPPS(b, s, e, g, TGL_LP) @@ -339,30 +331,30 @@ static const struct pinctrl_pin_desc tgllp_pins[] = { }; static const struct intel_padgroup tgllp_community0_gpps[] = { - TGL_GPP(0, 0, 25, 0), /* GPP_B */ - TGL_GPP(1, 26, 41, 32), /* GPP_T */ - TGL_GPP(2, 42, 66, 64), /* GPP_A */ + INTEL_GPP(0, 0, 25, 0), /* GPP_B */ + INTEL_GPP(1, 26, 41, 32), /* GPP_T */ + INTEL_GPP(2, 42, 66, 64), /* GPP_A */ }; static const struct intel_padgroup tgllp_community1_gpps[] = { - TGL_GPP(0, 67, 74, 96), /* GPP_S */ - TGL_GPP(1, 75, 98, 128), /* GPP_H */ - TGL_GPP(2, 99, 119, 160), /* GPP_D */ - TGL_GPP(3, 120, 143, 192), /* GPP_U */ - TGL_GPP(4, 144, 170, 224), /* vGPIO */ + INTEL_GPP(0, 67, 74, 96), /* GPP_S */ + INTEL_GPP(1, 75, 98, 128), /* GPP_H */ + INTEL_GPP(2, 99, 119, 160), /* GPP_D */ + INTEL_GPP(3, 120, 143, 192), /* GPP_U */ + INTEL_GPP(4, 144, 170, 224), /* vGPIO */ }; static const struct intel_padgroup tgllp_community4_gpps[] = { - TGL_GPP(0, 171, 194, 256), /* GPP_C */ - TGL_GPP(1, 195, 219, 288), /* GPP_F */ - TGL_GPP(2, 220, 225, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ - TGL_GPP(3, 226, 250, 320), /* GPP_E */ - TGL_GPP(4, 251, 259, INTEL_GPIO_BASE_NOMAP), /* JTAG */ + INTEL_GPP(0, 171, 194, 256), /* GPP_C */ + INTEL_GPP(1, 195, 219, 288), /* GPP_F */ + INTEL_GPP(2, 220, 225, INTEL_GPIO_BASE_NOMAP), /* HVCMOS */ + INTEL_GPP(3, 226, 250, 320), /* GPP_E */ + INTEL_GPP(4, 251, 259, INTEL_GPIO_BASE_NOMAP), /* JTAG */ }; static const struct intel_padgroup tgllp_community5_gpps[] = { - TGL_GPP(0, 260, 267, 352), /* GPP_R */ - TGL_GPP(1, 268, 276, INTEL_GPIO_BASE_NOMAP), /* SPI */ + INTEL_GPP(0, 260, 267, 352), /* GPP_R */ + INTEL_GPP(1, 268, 276, INTEL_GPIO_BASE_NOMAP), /* SPI */ }; static const struct intel_community tgllp_communities[] = { @@ -691,34 +683,34 @@ static const struct pinctrl_pin_desc tglh_pins[] = { }; static const struct intel_padgroup tglh_community0_gpps[] = { - TGL_GPP(0, 0, 24, 0), /* GPP_A */ - TGL_GPP(1, 25, 44, 32), /* GPP_R */ - TGL_GPP(2, 45, 70, 64), /* GPP_B */ - TGL_GPP(3, 71, 78, 96), /* vGPIO_0 */ + INTEL_GPP(0, 0, 24, 0), /* GPP_A */ + INTEL_GPP(1, 25, 44, 32), /* GPP_R */ + INTEL_GPP(2, 45, 70, 64), /* GPP_B */ + INTEL_GPP(3, 71, 78, 96), /* vGPIO_0 */ }; static const struct intel_padgroup tglh_community1_gpps[] = { - TGL_GPP(0, 79, 104, 128), /* GPP_D */ - TGL_GPP(1, 105, 128, 160), /* GPP_C */ - TGL_GPP(2, 129, 136, 192), /* GPP_S */ - TGL_GPP(3, 137, 153, 224), /* GPP_G */ - TGL_GPP(4, 154, 180, 256), /* vGPIO */ + INTEL_GPP(0, 79, 104, 128), /* GPP_D */ + INTEL_GPP(1, 105, 128, 160), /* GPP_C */ + INTEL_GPP(2, 129, 136, 192), /* GPP_S */ + INTEL_GPP(3, 137, 153, 224), /* GPP_G */ + INTEL_GPP(4, 154, 180, 256), /* vGPIO */ }; static const struct intel_padgroup tglh_community3_gpps[] = { - TGL_GPP(0, 181, 193, 288), /* GPP_E */ - TGL_GPP(1, 194, 217, 320), /* GPP_F */ + INTEL_GPP(0, 181, 193, 288), /* GPP_E */ + INTEL_GPP(1, 194, 217, 320), /* GPP_F */ }; static const struct intel_padgroup tglh_community4_gpps[] = { - TGL_GPP(0, 218, 241, 352), /* GPP_H */ - TGL_GPP(1, 242, 251, 384), /* GPP_J */ - TGL_GPP(2, 252, 266, 416), /* GPP_K */ + INTEL_GPP(0, 218, 241, 352), /* GPP_H */ + INTEL_GPP(1, 242, 251, 384), /* GPP_J */ + INTEL_GPP(2, 252, 266, 416), /* GPP_K */ }; static const struct intel_padgroup tglh_community5_gpps[] = { - TGL_GPP(0, 267, 281, 448), /* GPP_I */ - TGL_GPP(1, 282, 290, INTEL_GPIO_BASE_NOMAP), /* JTAG */ + INTEL_GPP(0, 267, 281, 448), /* GPP_I */ + INTEL_GPP(1, 282, 290, INTEL_GPIO_BASE_NOMAP), /* JTAG */ }; static const struct intel_community tglh_communities[] = { diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index 5b191e12a8aa..4819617d9368 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -181,6 +181,16 @@ config PINCTRL_MT6797 default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_PARIS +config PINCTRL_MT6878 + bool "MediaTek MT6878 pin control" + depends on OF + depends on ARM64 || COMPILE_TEST + default ARM64 && ARCH_MEDIATEK + select PINCTRL_MTK_PARIS + help + Say yes here to support pin controller and gpio driver + on the MediaTek MT6878 SoC. + config PINCTRL_MT6893 bool "MediaTek Dimensity MT6893 pin control" depends on OF diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile index 5d4646939ba3..ae765bd99965 100644 --- a/drivers/pinctrl/mediatek/Makefile +++ b/drivers/pinctrl/mediatek/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PINCTRL_MT6765) += pinctrl-mt6765.o obj-$(CONFIG_PINCTRL_MT6779) += pinctrl-mt6779.o obj-$(CONFIG_PINCTRL_MT6795) += pinctrl-mt6795.o obj-$(CONFIG_PINCTRL_MT6797) += pinctrl-mt6797.o +obj-$(CONFIG_PINCTRL_MT6878) += pinctrl-mt6878.o obj-$(CONFIG_PINCTRL_MT6893) += pinctrl-mt6893.o obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c index 9f175c73613f..c8c5097c11c4 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.c +++ b/drivers/pinctrl/mediatek/mtk-eint.c @@ -66,6 +66,11 @@ const unsigned int debounce_time_mt6795[] = { }; EXPORT_SYMBOL_GPL(debounce_time_mt6795); +const unsigned int debounce_time_mt6878[] = { + 156, 313, 625, 1250, 20000, 40000, 80000, 160000, 320000, 640000, 0 +}; +EXPORT_SYMBOL_GPL(debounce_time_mt6878); + static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint, unsigned int eint_num, unsigned int offset) diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h index fc31a4c0c77b..3cdd6f6310cd 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.h +++ b/drivers/pinctrl/mediatek/mtk-eint.h @@ -52,6 +52,7 @@ struct mtk_eint_pin { extern const unsigned int debounce_time_mt2701[]; extern const unsigned int debounce_time_mt6765[]; extern const unsigned int debounce_time_mt6795[]; +extern const unsigned int debounce_time_mt6878[]; struct mtk_eint; diff --git a/drivers/pinctrl/mediatek/pinctrl-airoha.c b/drivers/pinctrl/mediatek/pinctrl-airoha.c index f1cf2578fe42..995ba6175c95 100644 --- a/drivers/pinctrl/mediatek/pinctrl-airoha.c +++ b/drivers/pinctrl/mediatek/pinctrl-airoha.c @@ -30,15 +30,15 @@ #include "../pinconf.h" #include "../pinmux.h" -#define PINCTRL_PIN_GROUP(id) \ - PINCTRL_PINGROUP(#id, id##_pins, ARRAY_SIZE(id##_pins)) +#define PINCTRL_PIN_GROUP(id, table) \ + PINCTRL_PINGROUP(id, table##_pins, ARRAY_SIZE(table##_pins)) -#define PINCTRL_FUNC_DESC(id) \ +#define PINCTRL_FUNC_DESC(id, table) \ { \ - .desc = PINCTRL_PINFUNCTION(#id, id##_groups, \ - ARRAY_SIZE(id##_groups)), \ - .groups = id##_func_group, \ - .group_size = ARRAY_SIZE(id##_func_group), \ + .desc = PINCTRL_PINFUNCTION(id, table##_groups, \ + ARRAY_SIZE(table##_groups)),\ + .groups = table##_func_group, \ + .group_size = ARRAY_SIZE(table##_func_group), \ } #define PINCTRL_CONF_DESC(p, offset, mask) \ @@ -70,6 +70,7 @@ #define GPIO_PCM_SPI_CS3_MODE_MASK BIT(20) #define GPIO_PCM_SPI_CS2_MODE_P156_MASK BIT(19) #define GPIO_PCM_SPI_CS2_MODE_P128_MASK BIT(18) +#define AN7583_GPIO_PCM_SPI_CS2_MODE_MASK BIT(18) #define GPIO_PCM_SPI_CS1_MODE_MASK BIT(17) #define GPIO_PCM_SPI_MODE_MASK BIT(16) #define GPIO_PCM2_MODE_MASK BIT(13) @@ -127,6 +128,8 @@ /* CONF */ #define REG_I2C_SDA_E2 0x001c +#define AN7583_I2C1_SCL_E2_MASK BIT(16) +#define AN7583_I2C1_SDA_E2_MASK BIT(15) #define SPI_MISO_E2_MASK BIT(14) #define SPI_MOSI_E2_MASK BIT(13) #define SPI_CLK_E2_MASK BIT(12) @@ -134,12 +137,16 @@ #define PCIE2_RESET_E2_MASK BIT(10) #define PCIE1_RESET_E2_MASK BIT(9) #define PCIE0_RESET_E2_MASK BIT(8) +#define AN7583_MDIO_0_E2_MASK BIT(5) +#define AN7583_MDC_0_E2_MASK BIT(4) #define UART1_RXD_E2_MASK BIT(3) #define UART1_TXD_E2_MASK BIT(2) #define I2C_SCL_E2_MASK BIT(1) #define I2C_SDA_E2_MASK BIT(0) #define REG_I2C_SDA_E4 0x0020 +#define AN7583_I2C1_SCL_E4_MASK BIT(16) +#define AN7583_I2C1_SDA_E4_MASK BIT(15) #define SPI_MISO_E4_MASK BIT(14) #define SPI_MOSI_E4_MASK BIT(13) #define SPI_CLK_E4_MASK BIT(12) @@ -147,6 +154,8 @@ #define PCIE2_RESET_E4_MASK BIT(10) #define PCIE1_RESET_E4_MASK BIT(9) #define PCIE0_RESET_E4_MASK BIT(8) +#define AN7583_MDIO_0_E4_MASK BIT(5) +#define AN7583_MDC_0_E4_MASK BIT(4) #define UART1_RXD_E4_MASK BIT(3) #define UART1_TXD_E4_MASK BIT(2) #define I2C_SCL_E4_MASK BIT(1) @@ -158,6 +167,8 @@ #define REG_GPIO_H_E4 0x0030 #define REG_I2C_SDA_PU 0x0044 +#define AN7583_I2C1_SCL_PU_MASK BIT(16) +#define AN7583_I2C1_SDA_PU_MASK BIT(15) #define SPI_MISO_PU_MASK BIT(14) #define SPI_MOSI_PU_MASK BIT(13) #define SPI_CLK_PU_MASK BIT(12) @@ -165,12 +176,16 @@ #define PCIE2_RESET_PU_MASK BIT(10) #define PCIE1_RESET_PU_MASK BIT(9) #define PCIE0_RESET_PU_MASK BIT(8) +#define AN7583_MDIO_0_PU_MASK BIT(5) +#define AN7583_MDC_0_PU_MASK BIT(4) #define UART1_RXD_PU_MASK BIT(3) #define UART1_TXD_PU_MASK BIT(2) #define I2C_SCL_PU_MASK BIT(1) #define I2C_SDA_PU_MASK BIT(0) #define REG_I2C_SDA_PD 0x0048 +#define AN7583_I2C1_SDA_PD_MASK BIT(16) +#define AN7583_I2C1_SCL_PD_MASK BIT(15) #define SPI_MISO_PD_MASK BIT(14) #define SPI_MOSI_PD_MASK BIT(13) #define SPI_CLK_PD_MASK BIT(12) @@ -178,6 +193,8 @@ #define PCIE2_RESET_PD_MASK BIT(10) #define PCIE1_RESET_PD_MASK BIT(9) #define PCIE0_RESET_PD_MASK BIT(8) +#define AN7583_MDIO_0_PD_MASK BIT(5) +#define AN7583_MDC_0_PD_MASK BIT(4) #define UART1_RXD_PD_MASK BIT(3) #define UART1_TXD_PD_MASK BIT(2) #define I2C_SCL_PD_MASK BIT(1) @@ -357,16 +374,46 @@ struct airoha_pinctrl_gpiochip { u32 irq_type[AIROHA_NUM_PINS]; }; +struct airoha_pinctrl_confs_info { + const struct airoha_pinctrl_conf *confs; + unsigned int num_confs; +}; + +enum airoha_pinctrl_confs_type { + AIROHA_PINCTRL_CONFS_PULLUP, + AIROHA_PINCTRL_CONFS_PULLDOWN, + AIROHA_PINCTRL_CONFS_DRIVE_E2, + AIROHA_PINCTRL_CONFS_DRIVE_E4, + AIROHA_PINCTRL_CONFS_PCIE_RST_OD, + + AIROHA_PINCTRL_CONFS_MAX, +}; + struct airoha_pinctrl { struct pinctrl_dev *ctrl; + struct pinctrl_desc desc; + const struct pingroup *grps; + const struct airoha_pinctrl_func *funcs; + const struct airoha_pinctrl_confs_info *confs_info; + struct regmap *chip_scu; struct regmap *regmap; struct airoha_pinctrl_gpiochip gpiochip; }; -static struct pinctrl_pin_desc airoha_pinctrl_pins[] = { +struct airoha_pinctrl_match_data { + const struct pinctrl_pin_desc *pins; + const unsigned int num_pins; + const struct pingroup *grps; + const unsigned int num_grps; + const struct airoha_pinctrl_func *funcs; + const unsigned int num_funcs; + const struct airoha_pinctrl_confs_info confs_info[AIROHA_PINCTRL_CONFS_MAX]; +}; + +static struct pinctrl_pin_desc en7581_pinctrl_pins[] = { PINCTRL_PIN(0, "uart1_txd"), PINCTRL_PIN(1, "uart1_rxd"), PINCTRL_PIN(2, "i2c_scl"), @@ -427,178 +474,391 @@ static struct pinctrl_pin_desc airoha_pinctrl_pins[] = { PINCTRL_PIN(63, "pcie_reset2"), }; -static const int pon_pins[] = { 49, 50, 51, 52, 53, 54 }; -static const int pon_tod_1pps_pins[] = { 46 }; -static const int gsw_tod_1pps_pins[] = { 46 }; -static const int sipo_pins[] = { 16, 17 }; -static const int sipo_rclk_pins[] = { 16, 17, 43 }; -static const int mdio_pins[] = { 14, 15 }; -static const int uart2_pins[] = { 48, 55 }; -static const int uart2_cts_rts_pins[] = { 46, 47 }; -static const int hsuart_pins[] = { 28, 29 }; -static const int hsuart_cts_rts_pins[] = { 26, 27 }; -static const int uart4_pins[] = { 38, 39 }; -static const int uart5_pins[] = { 18, 19 }; -static const int i2c0_pins[] = { 2, 3 }; -static const int i2c1_pins[] = { 14, 15 }; -static const int jtag_udi_pins[] = { 16, 17, 18, 19, 20 }; -static const int jtag_dfd_pins[] = { 16, 17, 18, 19, 20 }; -static const int i2s_pins[] = { 26, 27, 28, 29 }; -static const int pcm1_pins[] = { 22, 23, 24, 25 }; -static const int pcm2_pins[] = { 18, 19, 20, 21 }; -static const int spi_quad_pins[] = { 32, 33 }; -static const int spi_pins[] = { 4, 5, 6, 7 }; -static const int spi_cs1_pins[] = { 34 }; -static const int pcm_spi_pins[] = { 18, 19, 20, 21, 22, 23, 24, 25 }; -static const int pcm_spi_int_pins[] = { 14 }; -static const int pcm_spi_rst_pins[] = { 15 }; -static const int pcm_spi_cs1_pins[] = { 43 }; -static const int pcm_spi_cs2_pins[] = { 40 }; -static const int pcm_spi_cs2_p128_pins[] = { 40 }; -static const int pcm_spi_cs2_p156_pins[] = { 40 }; -static const int pcm_spi_cs3_pins[] = { 41 }; -static const int pcm_spi_cs4_pins[] = { 42 }; -static const int emmc_pins[] = { 4, 5, 6, 30, 31, 32, 33, 34, 35, 36, 37 }; -static const int pnand_pins[] = { 4, 5, 6, 7, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42 }; -static const int gpio0_pins[] = { 13 }; -static const int gpio1_pins[] = { 14 }; -static const int gpio2_pins[] = { 15 }; -static const int gpio3_pins[] = { 16 }; -static const int gpio4_pins[] = { 17 }; -static const int gpio5_pins[] = { 18 }; -static const int gpio6_pins[] = { 19 }; -static const int gpio7_pins[] = { 20 }; -static const int gpio8_pins[] = { 21 }; -static const int gpio9_pins[] = { 22 }; -static const int gpio10_pins[] = { 23 }; -static const int gpio11_pins[] = { 24 }; -static const int gpio12_pins[] = { 25 }; -static const int gpio13_pins[] = { 26 }; -static const int gpio14_pins[] = { 27 }; -static const int gpio15_pins[] = { 28 }; -static const int gpio16_pins[] = { 29 }; -static const int gpio17_pins[] = { 30 }; -static const int gpio18_pins[] = { 31 }; -static const int gpio19_pins[] = { 32 }; -static const int gpio20_pins[] = { 33 }; -static const int gpio21_pins[] = { 34 }; -static const int gpio22_pins[] = { 35 }; -static const int gpio23_pins[] = { 36 }; -static const int gpio24_pins[] = { 37 }; -static const int gpio25_pins[] = { 38 }; -static const int gpio26_pins[] = { 39 }; -static const int gpio27_pins[] = { 40 }; -static const int gpio28_pins[] = { 41 }; -static const int gpio29_pins[] = { 42 }; -static const int gpio30_pins[] = { 43 }; -static const int gpio31_pins[] = { 44 }; -static const int gpio33_pins[] = { 46 }; -static const int gpio34_pins[] = { 47 }; -static const int gpio35_pins[] = { 48 }; -static const int gpio36_pins[] = { 49 }; -static const int gpio37_pins[] = { 50 }; -static const int gpio38_pins[] = { 51 }; -static const int gpio39_pins[] = { 52 }; -static const int gpio40_pins[] = { 53 }; -static const int gpio41_pins[] = { 54 }; -static const int gpio42_pins[] = { 55 }; -static const int gpio43_pins[] = { 56 }; -static const int gpio44_pins[] = { 57 }; -static const int gpio45_pins[] = { 58 }; -static const int gpio46_pins[] = { 59 }; -static const int pcie_reset0_pins[] = { 61 }; -static const int pcie_reset1_pins[] = { 62 }; -static const int pcie_reset2_pins[] = { 63 }; - -static const struct pingroup airoha_pinctrl_groups[] = { - PINCTRL_PIN_GROUP(pon), - PINCTRL_PIN_GROUP(pon_tod_1pps), - PINCTRL_PIN_GROUP(gsw_tod_1pps), - PINCTRL_PIN_GROUP(sipo), - PINCTRL_PIN_GROUP(sipo_rclk), - PINCTRL_PIN_GROUP(mdio), - PINCTRL_PIN_GROUP(uart2), - PINCTRL_PIN_GROUP(uart2_cts_rts), - PINCTRL_PIN_GROUP(hsuart), - PINCTRL_PIN_GROUP(hsuart_cts_rts), - PINCTRL_PIN_GROUP(uart4), - PINCTRL_PIN_GROUP(uart5), - PINCTRL_PIN_GROUP(i2c0), - PINCTRL_PIN_GROUP(i2c1), - PINCTRL_PIN_GROUP(jtag_udi), - PINCTRL_PIN_GROUP(jtag_dfd), - PINCTRL_PIN_GROUP(i2s), - PINCTRL_PIN_GROUP(pcm1), - PINCTRL_PIN_GROUP(pcm2), - PINCTRL_PIN_GROUP(spi), - PINCTRL_PIN_GROUP(spi_quad), - PINCTRL_PIN_GROUP(spi_cs1), - PINCTRL_PIN_GROUP(pcm_spi), - PINCTRL_PIN_GROUP(pcm_spi_int), - PINCTRL_PIN_GROUP(pcm_spi_rst), - PINCTRL_PIN_GROUP(pcm_spi_cs1), - PINCTRL_PIN_GROUP(pcm_spi_cs2_p128), - PINCTRL_PIN_GROUP(pcm_spi_cs2_p156), - PINCTRL_PIN_GROUP(pcm_spi_cs2), - PINCTRL_PIN_GROUP(pcm_spi_cs3), - PINCTRL_PIN_GROUP(pcm_spi_cs4), - PINCTRL_PIN_GROUP(emmc), - PINCTRL_PIN_GROUP(pnand), - PINCTRL_PIN_GROUP(gpio0), - PINCTRL_PIN_GROUP(gpio1), - PINCTRL_PIN_GROUP(gpio2), - PINCTRL_PIN_GROUP(gpio3), - PINCTRL_PIN_GROUP(gpio4), - PINCTRL_PIN_GROUP(gpio5), - PINCTRL_PIN_GROUP(gpio6), - PINCTRL_PIN_GROUP(gpio7), - PINCTRL_PIN_GROUP(gpio8), - PINCTRL_PIN_GROUP(gpio9), - PINCTRL_PIN_GROUP(gpio10), - PINCTRL_PIN_GROUP(gpio11), - PINCTRL_PIN_GROUP(gpio12), - PINCTRL_PIN_GROUP(gpio13), - PINCTRL_PIN_GROUP(gpio14), - PINCTRL_PIN_GROUP(gpio15), - PINCTRL_PIN_GROUP(gpio16), - PINCTRL_PIN_GROUP(gpio17), - PINCTRL_PIN_GROUP(gpio18), - PINCTRL_PIN_GROUP(gpio19), - PINCTRL_PIN_GROUP(gpio20), - PINCTRL_PIN_GROUP(gpio21), - PINCTRL_PIN_GROUP(gpio22), - PINCTRL_PIN_GROUP(gpio23), - PINCTRL_PIN_GROUP(gpio24), - PINCTRL_PIN_GROUP(gpio25), - PINCTRL_PIN_GROUP(gpio26), - PINCTRL_PIN_GROUP(gpio27), - PINCTRL_PIN_GROUP(gpio28), - PINCTRL_PIN_GROUP(gpio29), - PINCTRL_PIN_GROUP(gpio30), - PINCTRL_PIN_GROUP(gpio31), - PINCTRL_PIN_GROUP(gpio33), - PINCTRL_PIN_GROUP(gpio34), - PINCTRL_PIN_GROUP(gpio35), - PINCTRL_PIN_GROUP(gpio36), - PINCTRL_PIN_GROUP(gpio37), - PINCTRL_PIN_GROUP(gpio38), - PINCTRL_PIN_GROUP(gpio39), - PINCTRL_PIN_GROUP(gpio40), - PINCTRL_PIN_GROUP(gpio41), - PINCTRL_PIN_GROUP(gpio42), - PINCTRL_PIN_GROUP(gpio43), - PINCTRL_PIN_GROUP(gpio44), - PINCTRL_PIN_GROUP(gpio45), - PINCTRL_PIN_GROUP(gpio46), - PINCTRL_PIN_GROUP(pcie_reset0), - PINCTRL_PIN_GROUP(pcie_reset1), - PINCTRL_PIN_GROUP(pcie_reset2), +static const int en7581_pon_pins[] = { 49, 50, 51, 52, 53, 54 }; +static const int en7581_pon_tod_1pps_pins[] = { 46 }; +static const int en7581_gsw_tod_1pps_pins[] = { 46 }; +static const int en7581_sipo_pins[] = { 16, 17 }; +static const int en7581_sipo_rclk_pins[] = { 16, 17, 43 }; +static const int en7581_mdio_pins[] = { 14, 15 }; +static const int en7581_uart2_pins[] = { 48, 55 }; +static const int en7581_uart2_cts_rts_pins[] = { 46, 47 }; +static const int en7581_hsuart_pins[] = { 28, 29 }; +static const int en7581_hsuart_cts_rts_pins[] = { 26, 27 }; +static const int en7581_uart4_pins[] = { 38, 39 }; +static const int en7581_uart5_pins[] = { 18, 19 }; +static const int en7581_i2c0_pins[] = { 2, 3 }; +static const int en7581_i2c1_pins[] = { 14, 15 }; +static const int en7581_jtag_udi_pins[] = { 16, 17, 18, 19, 20 }; +static const int en7581_jtag_dfd_pins[] = { 16, 17, 18, 19, 20 }; +static const int en7581_i2s_pins[] = { 26, 27, 28, 29 }; +static const int en7581_pcm1_pins[] = { 22, 23, 24, 25 }; +static const int en7581_pcm2_pins[] = { 18, 19, 20, 21 }; +static const int en7581_spi_quad_pins[] = { 32, 33 }; +static const int en7581_spi_pins[] = { 4, 5, 6, 7 }; +static const int en7581_spi_cs1_pins[] = { 34 }; +static const int en7581_pcm_spi_pins[] = { 18, 19, 20, 21, 22, 23, 24, 25 }; +static const int en7581_pcm_spi_int_pins[] = { 14 }; +static const int en7581_pcm_spi_rst_pins[] = { 15 }; +static const int en7581_pcm_spi_cs1_pins[] = { 43 }; +static const int en7581_pcm_spi_cs2_pins[] = { 40 }; +static const int en7581_pcm_spi_cs2_p128_pins[] = { 40 }; +static const int en7581_pcm_spi_cs2_p156_pins[] = { 40 }; +static const int en7581_pcm_spi_cs3_pins[] = { 41 }; +static const int en7581_pcm_spi_cs4_pins[] = { 42 }; +static const int en7581_emmc_pins[] = { 4, 5, 6, 30, 31, 32, 33, 34, 35, 36, 37 }; +static const int en7581_pnand_pins[] = { 4, 5, 6, 7, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42 }; +static const int en7581_gpio0_pins[] = { 13 }; +static const int en7581_gpio1_pins[] = { 14 }; +static const int en7581_gpio2_pins[] = { 15 }; +static const int en7581_gpio3_pins[] = { 16 }; +static const int en7581_gpio4_pins[] = { 17 }; +static const int en7581_gpio5_pins[] = { 18 }; +static const int en7581_gpio6_pins[] = { 19 }; +static const int en7581_gpio7_pins[] = { 20 }; +static const int en7581_gpio8_pins[] = { 21 }; +static const int en7581_gpio9_pins[] = { 22 }; +static const int en7581_gpio10_pins[] = { 23 }; +static const int en7581_gpio11_pins[] = { 24 }; +static const int en7581_gpio12_pins[] = { 25 }; +static const int en7581_gpio13_pins[] = { 26 }; +static const int en7581_gpio14_pins[] = { 27 }; +static const int en7581_gpio15_pins[] = { 28 }; +static const int en7581_gpio16_pins[] = { 29 }; +static const int en7581_gpio17_pins[] = { 30 }; +static const int en7581_gpio18_pins[] = { 31 }; +static const int en7581_gpio19_pins[] = { 32 }; +static const int en7581_gpio20_pins[] = { 33 }; +static const int en7581_gpio21_pins[] = { 34 }; +static const int en7581_gpio22_pins[] = { 35 }; +static const int en7581_gpio23_pins[] = { 36 }; +static const int en7581_gpio24_pins[] = { 37 }; +static const int en7581_gpio25_pins[] = { 38 }; +static const int en7581_gpio26_pins[] = { 39 }; +static const int en7581_gpio27_pins[] = { 40 }; +static const int en7581_gpio28_pins[] = { 41 }; +static const int en7581_gpio29_pins[] = { 42 }; +static const int en7581_gpio30_pins[] = { 43 }; +static const int en7581_gpio31_pins[] = { 44 }; +static const int en7581_gpio33_pins[] = { 46 }; +static const int en7581_gpio34_pins[] = { 47 }; +static const int en7581_gpio35_pins[] = { 48 }; +static const int en7581_gpio36_pins[] = { 49 }; +static const int en7581_gpio37_pins[] = { 50 }; +static const int en7581_gpio38_pins[] = { 51 }; +static const int en7581_gpio39_pins[] = { 52 }; +static const int en7581_gpio40_pins[] = { 53 }; +static const int en7581_gpio41_pins[] = { 54 }; +static const int en7581_gpio42_pins[] = { 55 }; +static const int en7581_gpio43_pins[] = { 56 }; +static const int en7581_gpio44_pins[] = { 57 }; +static const int en7581_gpio45_pins[] = { 58 }; +static const int en7581_gpio46_pins[] = { 59 }; +static const int en7581_pcie_reset0_pins[] = { 61 }; +static const int en7581_pcie_reset1_pins[] = { 62 }; +static const int en7581_pcie_reset2_pins[] = { 63 }; + +static const struct pingroup en7581_pinctrl_groups[] = { + PINCTRL_PIN_GROUP("pon", en7581_pon), + PINCTRL_PIN_GROUP("pon_tod_1pps", en7581_pon_tod_1pps), + PINCTRL_PIN_GROUP("gsw_tod_1pps", en7581_gsw_tod_1pps), + PINCTRL_PIN_GROUP("sipo", en7581_sipo), + PINCTRL_PIN_GROUP("sipo_rclk", en7581_sipo_rclk), + PINCTRL_PIN_GROUP("mdio", en7581_mdio), + PINCTRL_PIN_GROUP("uart2", en7581_uart2), + PINCTRL_PIN_GROUP("uart2_cts_rts", en7581_uart2_cts_rts), + PINCTRL_PIN_GROUP("hsuart", en7581_hsuart), + PINCTRL_PIN_GROUP("hsuart_cts_rts", en7581_hsuart_cts_rts), + PINCTRL_PIN_GROUP("uart4", en7581_uart4), + PINCTRL_PIN_GROUP("uart5", en7581_uart5), + PINCTRL_PIN_GROUP("i2c0", en7581_i2c0), + PINCTRL_PIN_GROUP("i2c1", en7581_i2c1), + PINCTRL_PIN_GROUP("jtag_udi", en7581_jtag_udi), + PINCTRL_PIN_GROUP("jtag_dfd", en7581_jtag_dfd), + PINCTRL_PIN_GROUP("i2s", en7581_i2s), + PINCTRL_PIN_GROUP("pcm1", en7581_pcm1), + PINCTRL_PIN_GROUP("pcm2", en7581_pcm2), + PINCTRL_PIN_GROUP("spi", en7581_spi), + PINCTRL_PIN_GROUP("spi_quad", en7581_spi_quad), + PINCTRL_PIN_GROUP("spi_cs1", en7581_spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi", en7581_pcm_spi), + PINCTRL_PIN_GROUP("pcm_spi_int", en7581_pcm_spi_int), + PINCTRL_PIN_GROUP("pcm_spi_rst", en7581_pcm_spi_rst), + PINCTRL_PIN_GROUP("pcm_spi_cs1", en7581_pcm_spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi_cs2_p128", en7581_pcm_spi_cs2_p128), + PINCTRL_PIN_GROUP("pcm_spi_cs2_p156", en7581_pcm_spi_cs2_p156), + PINCTRL_PIN_GROUP("pcm_spi_cs2", en7581_pcm_spi_cs2), + PINCTRL_PIN_GROUP("pcm_spi_cs3", en7581_pcm_spi_cs3), + PINCTRL_PIN_GROUP("pcm_spi_cs4", en7581_pcm_spi_cs4), + PINCTRL_PIN_GROUP("emmc", en7581_emmc), + PINCTRL_PIN_GROUP("pnand", en7581_pnand), + PINCTRL_PIN_GROUP("gpio0", en7581_gpio0), + PINCTRL_PIN_GROUP("gpio1", en7581_gpio1), + PINCTRL_PIN_GROUP("gpio2", en7581_gpio2), + PINCTRL_PIN_GROUP("gpio3", en7581_gpio3), + PINCTRL_PIN_GROUP("gpio4", en7581_gpio4), + PINCTRL_PIN_GROUP("gpio5", en7581_gpio5), + PINCTRL_PIN_GROUP("gpio6", en7581_gpio6), + PINCTRL_PIN_GROUP("gpio7", en7581_gpio7), + PINCTRL_PIN_GROUP("gpio8", en7581_gpio8), + PINCTRL_PIN_GROUP("gpio9", en7581_gpio9), + PINCTRL_PIN_GROUP("gpio10", en7581_gpio10), + PINCTRL_PIN_GROUP("gpio11", en7581_gpio11), + PINCTRL_PIN_GROUP("gpio12", en7581_gpio12), + PINCTRL_PIN_GROUP("gpio13", en7581_gpio13), + PINCTRL_PIN_GROUP("gpio14", en7581_gpio14), + PINCTRL_PIN_GROUP("gpio15", en7581_gpio15), + PINCTRL_PIN_GROUP("gpio16", en7581_gpio16), + PINCTRL_PIN_GROUP("gpio17", en7581_gpio17), + PINCTRL_PIN_GROUP("gpio18", en7581_gpio18), + PINCTRL_PIN_GROUP("gpio19", en7581_gpio19), + PINCTRL_PIN_GROUP("gpio20", en7581_gpio20), + PINCTRL_PIN_GROUP("gpio21", en7581_gpio21), + PINCTRL_PIN_GROUP("gpio22", en7581_gpio22), + PINCTRL_PIN_GROUP("gpio23", en7581_gpio23), + PINCTRL_PIN_GROUP("gpio24", en7581_gpio24), + PINCTRL_PIN_GROUP("gpio25", en7581_gpio25), + PINCTRL_PIN_GROUP("gpio26", en7581_gpio26), + PINCTRL_PIN_GROUP("gpio27", en7581_gpio27), + PINCTRL_PIN_GROUP("gpio28", en7581_gpio28), + PINCTRL_PIN_GROUP("gpio29", en7581_gpio29), + PINCTRL_PIN_GROUP("gpio30", en7581_gpio30), + PINCTRL_PIN_GROUP("gpio31", en7581_gpio31), + PINCTRL_PIN_GROUP("gpio33", en7581_gpio33), + PINCTRL_PIN_GROUP("gpio34", en7581_gpio34), + PINCTRL_PIN_GROUP("gpio35", en7581_gpio35), + PINCTRL_PIN_GROUP("gpio36", en7581_gpio36), + PINCTRL_PIN_GROUP("gpio37", en7581_gpio37), + PINCTRL_PIN_GROUP("gpio38", en7581_gpio38), + PINCTRL_PIN_GROUP("gpio39", en7581_gpio39), + PINCTRL_PIN_GROUP("gpio40", en7581_gpio40), + PINCTRL_PIN_GROUP("gpio41", en7581_gpio41), + PINCTRL_PIN_GROUP("gpio42", en7581_gpio42), + PINCTRL_PIN_GROUP("gpio43", en7581_gpio43), + PINCTRL_PIN_GROUP("gpio44", en7581_gpio44), + PINCTRL_PIN_GROUP("gpio45", en7581_gpio45), + PINCTRL_PIN_GROUP("gpio46", en7581_gpio46), + PINCTRL_PIN_GROUP("pcie_reset0", en7581_pcie_reset0), + PINCTRL_PIN_GROUP("pcie_reset1", en7581_pcie_reset1), + PINCTRL_PIN_GROUP("pcie_reset2", en7581_pcie_reset2), +}; + +static struct pinctrl_pin_desc an7583_pinctrl_pins[] = { + PINCTRL_PIN(2, "gpio0"), + PINCTRL_PIN(3, "gpio1"), + PINCTRL_PIN(4, "gpio2"), + PINCTRL_PIN(5, "gpio3"), + PINCTRL_PIN(6, "gpio4"), + PINCTRL_PIN(7, "gpio5"), + PINCTRL_PIN(8, "gpio6"), + PINCTRL_PIN(9, "gpio7"), + PINCTRL_PIN(10, "gpio8"), + PINCTRL_PIN(11, "gpio9"), + PINCTRL_PIN(12, "gpio10"), + PINCTRL_PIN(13, "gpio11"), + PINCTRL_PIN(14, "gpio12"), + PINCTRL_PIN(15, "gpio13"), + PINCTRL_PIN(16, "gpio14"), + PINCTRL_PIN(17, "gpio15"), + PINCTRL_PIN(18, "gpio16"), + PINCTRL_PIN(19, "gpio17"), + PINCTRL_PIN(20, "gpio18"), + PINCTRL_PIN(21, "gpio19"), + PINCTRL_PIN(22, "gpio20"), + PINCTRL_PIN(23, "gpio21"), + PINCTRL_PIN(24, "gpio22"), + PINCTRL_PIN(25, "gpio23"), + PINCTRL_PIN(26, "gpio24"), + PINCTRL_PIN(27, "gpio25"), + PINCTRL_PIN(28, "gpio26"), + PINCTRL_PIN(29, "gpio27"), + PINCTRL_PIN(30, "gpio28"), + PINCTRL_PIN(31, "gpio29"), + PINCTRL_PIN(32, "gpio30"), + PINCTRL_PIN(33, "gpio31"), + PINCTRL_PIN(34, "gpio32"), + PINCTRL_PIN(35, "gpio33"), + PINCTRL_PIN(36, "gpio34"), + PINCTRL_PIN(37, "gpio35"), + PINCTRL_PIN(38, "gpio36"), + PINCTRL_PIN(39, "gpio37"), + PINCTRL_PIN(40, "gpio38"), + PINCTRL_PIN(41, "i2c0_scl"), + PINCTRL_PIN(42, "i2c0_sda"), + PINCTRL_PIN(43, "i2c1_scl"), + PINCTRL_PIN(44, "i2c1_sda"), + PINCTRL_PIN(45, "spi_clk"), + PINCTRL_PIN(46, "spi_cs"), + PINCTRL_PIN(47, "spi_mosi"), + PINCTRL_PIN(48, "spi_miso"), + PINCTRL_PIN(49, "uart_txd"), + PINCTRL_PIN(50, "uart_rxd"), + PINCTRL_PIN(51, "pcie_reset0"), + PINCTRL_PIN(52, "pcie_reset1"), + PINCTRL_PIN(53, "mdc_0"), + PINCTRL_PIN(54, "mdio_0"), +}; + +static const int an7583_pon_pins[] = { 15, 16, 17, 18, 19, 20 }; +static const int an7583_pon_tod_1pps_pins[] = { 32 }; +static const int an7583_gsw_tod_1pps_pins[] = { 32 }; +static const int an7583_sipo_pins[] = { 34, 35 }; +static const int an7583_sipo_rclk_pins[] = { 34, 35, 33 }; +static const int an7583_mdio_pins[] = { 43, 44 }; +static const int an7583_uart2_pins[] = { 34, 35 }; +static const int an7583_uart2_cts_rts_pins[] = { 32, 33 }; +static const int an7583_hsuart_pins[] = { 30, 31 }; +static const int an7583_hsuart_cts_rts_pins[] = { 28, 29 }; +static const int an7583_npu_uart_pins[] = { 7, 8 }; +static const int an7583_uart4_pins[] = { 7, 8 }; +static const int an7583_uart5_pins[] = { 23, 24 }; +static const int an7583_i2c0_pins[] = { 41, 42 }; +static const int an7583_i2c1_pins[] = { 43, 44 }; +static const int an7583_jtag_udi_pins[] = { 23, 24, 22, 25, 26 }; +static const int an7583_jtag_dfd_pins[] = { 23, 24, 22, 25, 26 }; +static const int an7583_pcm1_pins[] = { 10, 11, 12, 13, 14 }; +static const int an7583_pcm2_pins[] = { 28, 29, 30, 31, 24 }; +static const int an7583_spi_pins[] = { 28, 29, 30, 31 }; +static const int an7583_spi_quad_pins[] = { 25, 26 }; +static const int an7583_spi_cs1_pins[] = { 27 }; +static const int an7583_pcm_spi_pins[] = { 28, 29, 30, 31, 10, 11, 12, 13 }; +static const int an7583_pcm_spi_rst_pins[] = { 14 }; +static const int an7583_pcm_spi_cs1_pins[] = { 24 }; +static const int an7583_emmc_pins[] = { 7, 8, 9, 22, 23, 24, 25, 26, 45, 46, 47 }; +static const int an7583_pnand_pins[] = { 7, 8, 9, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 45, 46, 47, 48 }; +static const int an7583_gpio0_pins[] = { 2 }; +static const int an7583_gpio1_pins[] = { 3 }; +static const int an7583_gpio2_pins[] = { 4 }; +static const int an7583_gpio3_pins[] = { 5 }; +static const int an7583_gpio4_pins[] = { 6 }; +static const int an7583_gpio5_pins[] = { 7 }; +static const int an7583_gpio6_pins[] = { 8 }; +static const int an7583_gpio7_pins[] = { 9 }; +static const int an7583_gpio8_pins[] = { 10 }; +static const int an7583_gpio9_pins[] = { 11 }; +static const int an7583_gpio10_pins[] = { 12 }; +static const int an7583_gpio11_pins[] = { 13 }; +static const int an7583_gpio12_pins[] = { 14 }; +static const int an7583_gpio13_pins[] = { 15 }; +static const int an7583_gpio14_pins[] = { 16 }; +static const int an7583_gpio15_pins[] = { 17 }; +static const int an7583_gpio16_pins[] = { 18 }; +static const int an7583_gpio17_pins[] = { 19 }; +static const int an7583_gpio18_pins[] = { 20 }; +static const int an7583_gpio19_pins[] = { 21 }; +static const int an7583_gpio20_pins[] = { 22 }; +static const int an7583_gpio21_pins[] = { 24 }; +static const int an7583_gpio23_pins[] = { 25 }; +static const int an7583_gpio24_pins[] = { 26 }; +static const int an7583_gpio25_pins[] = { 27 }; +static const int an7583_gpio26_pins[] = { 28 }; +static const int an7583_gpio27_pins[] = { 29 }; +static const int an7583_gpio28_pins[] = { 30 }; +static const int an7583_gpio29_pins[] = { 31 }; +static const int an7583_gpio30_pins[] = { 32 }; +static const int an7583_gpio31_pins[] = { 33 }; +static const int an7583_gpio33_pins[] = { 35 }; +static const int an7583_gpio34_pins[] = { 36 }; +static const int an7583_gpio35_pins[] = { 37 }; +static const int an7583_gpio36_pins[] = { 38 }; +static const int an7583_gpio37_pins[] = { 39 }; +static const int an7583_gpio38_pins[] = { 40 }; +static const int an7583_gpio39_pins[] = { 41 }; +static const int an7583_gpio40_pins[] = { 42 }; +static const int an7583_gpio41_pins[] = { 43 }; +static const int an7583_gpio42_pins[] = { 44 }; +static const int an7583_gpio43_pins[] = { 45 }; +static const int an7583_gpio44_pins[] = { 46 }; +static const int an7583_gpio45_pins[] = { 47 }; +static const int an7583_gpio46_pins[] = { 48 }; +static const int an7583_gpio47_pins[] = { 49 }; +static const int an7583_gpio48_pins[] = { 50 }; +static const int an7583_pcie_reset0_pins[] = { 51 }; +static const int an7583_pcie_reset1_pins[] = { 52 }; + +static const struct pingroup an7583_pinctrl_groups[] = { + PINCTRL_PIN_GROUP("pon", an7583_pon), + PINCTRL_PIN_GROUP("pon_tod_1pps", an7583_pon_tod_1pps), + PINCTRL_PIN_GROUP("gsw_tod_1pps", an7583_gsw_tod_1pps), + PINCTRL_PIN_GROUP("sipo", an7583_sipo), + PINCTRL_PIN_GROUP("sipo_rclk", an7583_sipo_rclk), + PINCTRL_PIN_GROUP("mdio", an7583_mdio), + PINCTRL_PIN_GROUP("uart2", an7583_uart2), + PINCTRL_PIN_GROUP("uart2_cts_rts", an7583_uart2_cts_rts), + PINCTRL_PIN_GROUP("hsuart", an7583_hsuart), + PINCTRL_PIN_GROUP("hsuart_cts_rts", an7583_hsuart_cts_rts), + PINCTRL_PIN_GROUP("npu_uart", an7583_npu_uart), + PINCTRL_PIN_GROUP("uart4", an7583_uart4), + PINCTRL_PIN_GROUP("uart5", an7583_uart5), + PINCTRL_PIN_GROUP("i2c0", an7583_i2c0), + PINCTRL_PIN_GROUP("i2c1", an7583_i2c1), + PINCTRL_PIN_GROUP("jtag_udi", an7583_jtag_udi), + PINCTRL_PIN_GROUP("jtag_dfd", an7583_jtag_dfd), + PINCTRL_PIN_GROUP("pcm1", an7583_pcm1), + PINCTRL_PIN_GROUP("pcm2", an7583_pcm2), + PINCTRL_PIN_GROUP("spi", an7583_spi), + PINCTRL_PIN_GROUP("spi_quad", an7583_spi_quad), + PINCTRL_PIN_GROUP("spi_cs1", an7583_spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi", an7583_pcm_spi), + PINCTRL_PIN_GROUP("pcm_spi_rst", an7583_pcm_spi_rst), + PINCTRL_PIN_GROUP("pcm_spi_cs1", an7583_pcm_spi_cs1), + PINCTRL_PIN_GROUP("emmc", an7583_emmc), + PINCTRL_PIN_GROUP("pnand", an7583_pnand), + PINCTRL_PIN_GROUP("gpio0", an7583_gpio0), + PINCTRL_PIN_GROUP("gpio1", an7583_gpio1), + PINCTRL_PIN_GROUP("gpio2", an7583_gpio2), + PINCTRL_PIN_GROUP("gpio3", an7583_gpio3), + PINCTRL_PIN_GROUP("gpio4", an7583_gpio4), + PINCTRL_PIN_GROUP("gpio5", an7583_gpio5), + PINCTRL_PIN_GROUP("gpio6", an7583_gpio6), + PINCTRL_PIN_GROUP("gpio7", an7583_gpio7), + PINCTRL_PIN_GROUP("gpio8", an7583_gpio8), + PINCTRL_PIN_GROUP("gpio9", an7583_gpio9), + PINCTRL_PIN_GROUP("gpio10", an7583_gpio10), + PINCTRL_PIN_GROUP("gpio11", an7583_gpio11), + PINCTRL_PIN_GROUP("gpio12", an7583_gpio12), + PINCTRL_PIN_GROUP("gpio13", an7583_gpio13), + PINCTRL_PIN_GROUP("gpio14", an7583_gpio14), + PINCTRL_PIN_GROUP("gpio15", an7583_gpio15), + PINCTRL_PIN_GROUP("gpio16", an7583_gpio16), + PINCTRL_PIN_GROUP("gpio17", an7583_gpio17), + PINCTRL_PIN_GROUP("gpio18", an7583_gpio18), + PINCTRL_PIN_GROUP("gpio19", an7583_gpio19), + PINCTRL_PIN_GROUP("gpio20", an7583_gpio20), + PINCTRL_PIN_GROUP("gpio21", an7583_gpio21), + PINCTRL_PIN_GROUP("gpio23", an7583_gpio23), + PINCTRL_PIN_GROUP("gpio24", an7583_gpio24), + PINCTRL_PIN_GROUP("gpio25", an7583_gpio25), + PINCTRL_PIN_GROUP("gpio26", an7583_gpio26), + PINCTRL_PIN_GROUP("gpio27", an7583_gpio27), + PINCTRL_PIN_GROUP("gpio28", an7583_gpio28), + PINCTRL_PIN_GROUP("gpio29", an7583_gpio29), + PINCTRL_PIN_GROUP("gpio30", an7583_gpio30), + PINCTRL_PIN_GROUP("gpio31", an7583_gpio31), + PINCTRL_PIN_GROUP("gpio33", an7583_gpio33), + PINCTRL_PIN_GROUP("gpio34", an7583_gpio34), + PINCTRL_PIN_GROUP("gpio35", an7583_gpio35), + PINCTRL_PIN_GROUP("gpio36", an7583_gpio36), + PINCTRL_PIN_GROUP("gpio37", an7583_gpio37), + PINCTRL_PIN_GROUP("gpio38", an7583_gpio38), + PINCTRL_PIN_GROUP("gpio39", an7583_gpio39), + PINCTRL_PIN_GROUP("gpio40", an7583_gpio40), + PINCTRL_PIN_GROUP("gpio41", an7583_gpio41), + PINCTRL_PIN_GROUP("gpio42", an7583_gpio42), + PINCTRL_PIN_GROUP("gpio43", an7583_gpio43), + PINCTRL_PIN_GROUP("gpio44", an7583_gpio44), + PINCTRL_PIN_GROUP("gpio45", an7583_gpio45), + PINCTRL_PIN_GROUP("gpio46", an7583_gpio46), + PINCTRL_PIN_GROUP("gpio47", an7583_gpio47), + PINCTRL_PIN_GROUP("gpio48", an7583_gpio48), + PINCTRL_PIN_GROUP("pcie_reset0", an7583_pcie_reset0), + PINCTRL_PIN_GROUP("pcie_reset1", an7583_pcie_reset1), }; static const char *const pon_groups[] = { "pon" }; static const char *const tod_1pps_groups[] = { "pon_tod_1pps", "gsw_tod_1pps" }; static const char *const sipo_groups[] = { "sipo", "sipo_rclk" }; static const char *const mdio_groups[] = { "mdio" }; +static const char *const an7583_mdio_groups[] = { "mdio" }; static const char *const uart_groups[] = { "uart2", "uart2_cts_rts", "hsuart", "hsuart_cts_rts", "uart4", "uart5" }; @@ -611,11 +871,16 @@ static const char *const pcm_spi_groups[] = { "pcm_spi", "pcm_spi_int", "pcm_spi_cs2_p156", "pcm_spi_cs2_p128", "pcm_spi_cs3", "pcm_spi_cs4" }; +static const char *const an7583_pcm_spi_groups[] = { "pcm_spi", "pcm_spi_int", + "pcm_spi_rst", "pcm_spi_cs1", + "pcm_spi_cs2", "pcm_spi_cs3", + "pcm_spi_cs4" }; static const char *const i2s_groups[] = { "i2s" }; static const char *const emmc_groups[] = { "emmc" }; static const char *const pnand_groups[] = { "pnand" }; static const char *const pcie_reset_groups[] = { "pcie_reset0", "pcie_reset1", "pcie_reset2" }; +static const char *const an7583_pcie_reset_groups[] = { "pcie_reset0", "pcie_reset1" }; static const char *const pwm_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", @@ -654,6 +919,22 @@ static const char *const phy3_led1_groups[] = { "gpio43", "gpio44", "gpio45", "gpio46" }; static const char *const phy4_led1_groups[] = { "gpio43", "gpio44", "gpio45", "gpio46" }; +static const char *const an7583_phy1_led0_groups[] = { "gpio1", "gpio2", + "gpio3", "gpio4" }; +static const char *const an7583_phy2_led0_groups[] = { "gpio1", "gpio2", + "gpio3", "gpio4" }; +static const char *const an7583_phy3_led0_groups[] = { "gpio1", "gpio2", + "gpio3", "gpio4" }; +static const char *const an7583_phy4_led0_groups[] = { "gpio1", "gpio2", + "gpio3", "gpio4" }; +static const char *const an7583_phy1_led1_groups[] = { "gpio8", "gpio9", + "gpio10", "gpio11" }; +static const char *const an7583_phy2_led1_groups[] = { "gpio8", "gpio9", + "gpio10", "gpio11" }; +static const char *const an7583_phy3_led1_groups[] = { "gpio8", "gpio9", + "gpio10", "gpio11" }; +static const char *const an7583_phy4_led1_groups[] = { "gpio8", "gpio9", + "gpio10", "gpio11" }; static const struct airoha_pinctrl_func_group pon_func_group[] = { { @@ -731,6 +1012,25 @@ static const struct airoha_pinctrl_func_group mdio_func_group[] = { }, }; +static const struct airoha_pinctrl_func_group an7583_mdio_func_group[] = { + { + .name = "mdio", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SGMII_MDIO_MODE_MASK, + GPIO_SGMII_MDIO_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_MDC_IO_MASTER_MODE_MODE, + GPIO_MDC_IO_MASTER_MODE_MODE + }, + .regmap_size = 2, + }, +}; + static const struct airoha_pinctrl_func_group uart_func_group[] = { { .name = "uart2", @@ -972,6 +1272,73 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = { }, }; +static const struct airoha_pinctrl_func_group an7583_pcm_spi_func_group[] = { + { + .name = "pcm_spi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_MODE_MASK, + GPIO_PCM_SPI_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_int", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_INT_MODE_MASK, + GPIO_PCM_INT_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_rst", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_RESET_MODE_MASK, + GPIO_PCM_RESET_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS1_MODE_MASK, + GPIO_PCM_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + AN7583_GPIO_PCM_SPI_CS2_MODE_MASK, + AN7583_GPIO_PCM_SPI_CS2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS3_MODE_MASK, + GPIO_PCM_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS4_MODE_MASK, + GPIO_PCM_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + static const struct airoha_pinctrl_func_group i2s_func_group[] = { { .name = "i2s", @@ -1042,946 +1409,364 @@ static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = { }, }; -/* PWM */ -static const struct airoha_pinctrl_func_group pwm_func_group[] = { +static const struct airoha_pinctrl_func_group an7583_pcie_reset_func_group[] = { { - .name = "gpio0", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO0_FLASH_MODE_CFG, - GPIO0_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio1", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO1_FLASH_MODE_CFG, - GPIO1_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio2", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO2_FLASH_MODE_CFG, - GPIO2_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio3", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO3_FLASH_MODE_CFG, - GPIO3_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio4", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO4_FLASH_MODE_CFG, - GPIO4_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio5", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO5_FLASH_MODE_CFG, - GPIO5_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio6", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO6_FLASH_MODE_CFG, - GPIO6_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio7", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO7_FLASH_MODE_CFG, - GPIO7_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio8", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO8_FLASH_MODE_CFG, - GPIO8_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio9", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO9_FLASH_MODE_CFG, - GPIO9_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio10", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO10_FLASH_MODE_CFG, - GPIO10_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio11", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO11_FLASH_MODE_CFG, - GPIO11_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio12", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO12_FLASH_MODE_CFG, - GPIO12_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio13", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO13_FLASH_MODE_CFG, - GPIO13_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio14", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO14_FLASH_MODE_CFG, - GPIO14_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio15", - .regmap[0] = { - AIROHA_FUNC_PWM_MUX, - REG_GPIO_FLASH_MODE_CFG, - GPIO15_FLASH_MODE_CFG, - GPIO15_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio16", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO16_FLASH_MODE_CFG, - GPIO16_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio17", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO17_FLASH_MODE_CFG, - GPIO17_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio18", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO18_FLASH_MODE_CFG, - GPIO18_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio19", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO19_FLASH_MODE_CFG, - GPIO19_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio20", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO20_FLASH_MODE_CFG, - GPIO20_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio21", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO21_FLASH_MODE_CFG, - GPIO21_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio22", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO22_FLASH_MODE_CFG, - GPIO22_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio23", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO23_FLASH_MODE_CFG, - GPIO23_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio24", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO24_FLASH_MODE_CFG, - GPIO24_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio25", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO25_FLASH_MODE_CFG, - GPIO25_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio26", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO26_FLASH_MODE_CFG, - GPIO26_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio27", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO27_FLASH_MODE_CFG, - GPIO27_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio28", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO28_FLASH_MODE_CFG, - GPIO28_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio29", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO29_FLASH_MODE_CFG, - GPIO29_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio30", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO30_FLASH_MODE_CFG, - GPIO30_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio31", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO31_FLASH_MODE_CFG, - GPIO31_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio36", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO36_FLASH_MODE_CFG, - GPIO36_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio37", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO37_FLASH_MODE_CFG, - GPIO37_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio38", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO38_FLASH_MODE_CFG, - GPIO38_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio39", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO39_FLASH_MODE_CFG, - GPIO39_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio40", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO40_FLASH_MODE_CFG, - GPIO40_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio41", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO41_FLASH_MODE_CFG, - GPIO41_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio42", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO42_FLASH_MODE_CFG, - GPIO42_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio43", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO43_FLASH_MODE_CFG, - GPIO43_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio44", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO44_FLASH_MODE_CFG, - GPIO44_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio45", - .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO45_FLASH_MODE_CFG, - GPIO45_FLASH_MODE_CFG - }, - .regmap_size = 1, - }, { - .name = "gpio46", + .name = "pcie_reset0", .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO46_FLASH_MODE_CFG, - GPIO46_FLASH_MODE_CFG + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET0_MASK, + GPIO_PCIE_RESET0_MASK }, .regmap_size = 1, }, { - .name = "gpio47", + .name = "pcie_reset1", .regmap[0] = { - AIROHA_FUNC_PWM_EXT_MUX, - REG_GPIO_FLASH_MODE_CFG_EXT, - GPIO47_FLASH_MODE_CFG, - GPIO47_FLASH_MODE_CFG + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET1_MASK, + GPIO_PCIE_RESET1_MASK }, .regmap_size = 1, }, }; +/* PWM */ +#define AIROHA_PINCTRL_PWM(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_MUX, \ + REG_GPIO_FLASH_MODE_CFG, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } \ + +#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } \ + +static const struct airoha_pinctrl_func_group pwm_func_group[] = { + AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio28", GPIO28_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio29", GPIO29_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio30", GPIO30_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio31", GPIO31_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio36", GPIO36_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio37", GPIO37_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio38", GPIO38_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio39", GPIO39_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio40", GPIO40_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio41", GPIO41_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio42", GPIO42_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio43", GPIO43_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio44", GPIO44_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio45", GPIO45_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio46", GPIO46_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio47", GPIO47_FLASH_MODE_CFG), +}; + +#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_2ND_I2C_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED0_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + +#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_2ND_I2C_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED1_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = { - { - .name = "gpio33", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED0_MODE_MASK, - GPIO_LAN0_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, { - .name = "gpio34", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED0_MODE_MASK, - GPIO_LAN1_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, { - .name = "gpio35", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED0_MODE_MASK, - GPIO_LAN2_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, { - .name = "gpio42", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED0_MODE_MASK, - GPIO_LAN3_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), }; static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = { - { - .name = "gpio33", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED0_MODE_MASK, - GPIO_LAN0_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, { - .name = "gpio34", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED0_MODE_MASK, - GPIO_LAN1_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, { - .name = "gpio35", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED0_MODE_MASK, - GPIO_LAN2_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, { - .name = "gpio42", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED0_MODE_MASK, - GPIO_LAN3_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), }; static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = { - { - .name = "gpio33", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED0_MODE_MASK, - GPIO_LAN0_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, { - .name = "gpio34", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED0_MODE_MASK, - GPIO_LAN1_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, { - .name = "gpio35", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED0_MODE_MASK, - GPIO_LAN2_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, { - .name = "gpio42", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED0_MODE_MASK, - GPIO_LAN3_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), }; static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = { - { - .name = "gpio33", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED0_MODE_MASK, - GPIO_LAN0_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, { - .name = "gpio34", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED0_MODE_MASK, - GPIO_LAN1_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, { - .name = "gpio35", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED0_MODE_MASK, - GPIO_LAN2_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, { - .name = "gpio42", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED0_MODE_MASK, - GPIO_LAN3_LED0_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED0_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), }; static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = { - { - .name = "gpio43", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED1_MODE_MASK, - GPIO_LAN0_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, { - .name = "gpio44", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED1_MODE_MASK, - GPIO_LAN1_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, { - .name = "gpio45", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED1_MODE_MASK, - GPIO_LAN2_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, { - .name = "gpio46", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED1_MODE_MASK, - GPIO_LAN3_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(0) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), }; static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = { - { - .name = "gpio43", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED1_MODE_MASK, - GPIO_LAN0_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, { - .name = "gpio44", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED1_MODE_MASK, - GPIO_LAN1_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, { - .name = "gpio45", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED1_MODE_MASK, - GPIO_LAN2_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, { - .name = "gpio46", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED1_MODE_MASK, - GPIO_LAN3_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(1) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), }; static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = { - { - .name = "gpio43", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED1_MODE_MASK, - GPIO_LAN0_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, { - .name = "gpio44", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED1_MODE_MASK, - GPIO_LAN1_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, { - .name = "gpio45", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED1_MODE_MASK, - GPIO_LAN2_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, { - .name = "gpio46", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED1_MODE_MASK, - GPIO_LAN3_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(2) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), }; static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = { - { - .name = "gpio43", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN0_LED1_MODE_MASK, - GPIO_LAN0_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN0_LED_MAPPING_MASK, - LAN0_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, { - .name = "gpio44", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN1_LED1_MODE_MASK, - GPIO_LAN1_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN1_LED_MAPPING_MASK, - LAN1_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, { - .name = "gpio45", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN2_LED1_MODE_MASK, - GPIO_LAN2_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN2_LED_MAPPING_MASK, - LAN2_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, { - .name = "gpio46", - .regmap[0] = { - AIROHA_FUNC_MUX, - REG_GPIO_2ND_I2C_MODE, - GPIO_LAN3_LED1_MODE_MASK, - GPIO_LAN3_LED1_MODE_MASK - }, - .regmap[1] = { - AIROHA_FUNC_MUX, - REG_LAN_LED1_MAPPING, - LAN3_LED_MAPPING_MASK, - LAN3_PHY_LED_MAP(3) - }, - .regmap_size = 2, - }, + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group an7583_phy1_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group an7583_phy2_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group an7583_phy3_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group an7583_phy4_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), }; -static const struct airoha_pinctrl_func airoha_pinctrl_funcs[] = { - PINCTRL_FUNC_DESC(pon), - PINCTRL_FUNC_DESC(tod_1pps), - PINCTRL_FUNC_DESC(sipo), - PINCTRL_FUNC_DESC(mdio), - PINCTRL_FUNC_DESC(uart), - PINCTRL_FUNC_DESC(i2c), - PINCTRL_FUNC_DESC(jtag), - PINCTRL_FUNC_DESC(pcm), - PINCTRL_FUNC_DESC(spi), - PINCTRL_FUNC_DESC(pcm_spi), - PINCTRL_FUNC_DESC(i2s), - PINCTRL_FUNC_DESC(emmc), - PINCTRL_FUNC_DESC(pnand), - PINCTRL_FUNC_DESC(pcie_reset), - PINCTRL_FUNC_DESC(pwm), - PINCTRL_FUNC_DESC(phy1_led0), - PINCTRL_FUNC_DESC(phy2_led0), - PINCTRL_FUNC_DESC(phy3_led0), - PINCTRL_FUNC_DESC(phy4_led0), - PINCTRL_FUNC_DESC(phy1_led1), - PINCTRL_FUNC_DESC(phy2_led1), - PINCTRL_FUNC_DESC(phy3_led1), - PINCTRL_FUNC_DESC(phy4_led1), -}; - -static const struct airoha_pinctrl_conf airoha_pinctrl_pullup_conf[] = { +static const struct airoha_pinctrl_func_group an7583_phy1_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio1", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group an7583_phy2_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group an7583_phy3_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group an7583_phy4_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func en7581_pinctrl_funcs[] = { + PINCTRL_FUNC_DESC("pon", pon), + PINCTRL_FUNC_DESC("tod_1pps", tod_1pps), + PINCTRL_FUNC_DESC("sipo", sipo), + PINCTRL_FUNC_DESC("mdio", mdio), + PINCTRL_FUNC_DESC("uart", uart), + PINCTRL_FUNC_DESC("i2c", i2c), + PINCTRL_FUNC_DESC("jtag", jtag), + PINCTRL_FUNC_DESC("pcm", pcm), + PINCTRL_FUNC_DESC("spi", spi), + PINCTRL_FUNC_DESC("pcm_spi", pcm_spi), + PINCTRL_FUNC_DESC("i2s", i2s), + PINCTRL_FUNC_DESC("emmc", emmc), + PINCTRL_FUNC_DESC("pnand", pnand), + PINCTRL_FUNC_DESC("pcie_reset", pcie_reset), + PINCTRL_FUNC_DESC("pwm", pwm), + PINCTRL_FUNC_DESC("phy1_led0", phy1_led0), + PINCTRL_FUNC_DESC("phy2_led0", phy2_led0), + PINCTRL_FUNC_DESC("phy3_led0", phy3_led0), + PINCTRL_FUNC_DESC("phy4_led0", phy4_led0), + PINCTRL_FUNC_DESC("phy1_led1", phy1_led1), + PINCTRL_FUNC_DESC("phy2_led1", phy2_led1), + PINCTRL_FUNC_DESC("phy3_led1", phy3_led1), + PINCTRL_FUNC_DESC("phy4_led1", phy4_led1), +}; + +static const struct airoha_pinctrl_func an7583_pinctrl_funcs[] = { + PINCTRL_FUNC_DESC("pon", pon), + PINCTRL_FUNC_DESC("tod_1pps", tod_1pps), + PINCTRL_FUNC_DESC("sipo", sipo), + PINCTRL_FUNC_DESC("mdio", an7583_mdio), + PINCTRL_FUNC_DESC("uart", uart), + PINCTRL_FUNC_DESC("i2c", i2c), + PINCTRL_FUNC_DESC("jtag", jtag), + PINCTRL_FUNC_DESC("pcm", pcm), + PINCTRL_FUNC_DESC("spi", spi), + PINCTRL_FUNC_DESC("pcm_spi", an7583_pcm_spi), + PINCTRL_FUNC_DESC("emmc", emmc), + PINCTRL_FUNC_DESC("pnand", pnand), + PINCTRL_FUNC_DESC("pcie_reset", an7583_pcie_reset), + PINCTRL_FUNC_DESC("pwm", pwm), + PINCTRL_FUNC_DESC("phy1_led0", an7583_phy1_led0), + PINCTRL_FUNC_DESC("phy2_led0", an7583_phy2_led0), + PINCTRL_FUNC_DESC("phy3_led0", an7583_phy3_led0), + PINCTRL_FUNC_DESC("phy4_led0", an7583_phy4_led0), + PINCTRL_FUNC_DESC("phy1_led1", an7583_phy1_led1), + PINCTRL_FUNC_DESC("phy2_led1", an7583_phy2_led1), + PINCTRL_FUNC_DESC("phy3_led1", an7583_phy3_led1), + PINCTRL_FUNC_DESC("phy4_led1", an7583_phy4_led1), +}; + +static const struct airoha_pinctrl_conf en7581_pinctrl_pullup_conf[] = { PINCTRL_CONF_DESC(0, REG_I2C_SDA_PU, UART1_TXD_PU_MASK), PINCTRL_CONF_DESC(1, REG_I2C_SDA_PU, UART1_RXD_PU_MASK), PINCTRL_CONF_DESC(2, REG_I2C_SDA_PU, I2C_SDA_PU_MASK), @@ -2042,7 +1827,63 @@ static const struct airoha_pinctrl_conf airoha_pinctrl_pullup_conf[] = { PINCTRL_CONF_DESC(63, REG_I2C_SDA_PU, PCIE2_RESET_PU_MASK), }; -static const struct airoha_pinctrl_conf airoha_pinctrl_pulldown_conf[] = { +static const struct airoha_pinctrl_conf an7583_pinctrl_pullup_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_PU, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_PU, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_PU, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_PU, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_PU, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_PU, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_PU, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_PU, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_PU, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_PU, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_PU, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PU, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PU, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PU, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PU, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PU, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PU, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PU, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PU, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PU, BIT(18)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PU, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PU, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PU, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PU, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PU, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PU, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PU, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PU, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PU, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PU, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PU, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PU, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_PU, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_PU, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_PU, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_PU, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_PU, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_PU, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_PU, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_PU, I2C_SCL_PU_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_PU, I2C_SDA_PU_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_PU, AN7583_I2C1_SCL_PU_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_PU, AN7583_I2C1_SDA_PU_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_PU, SPI_CLK_PU_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_PU, SPI_CS0_PU_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_PU, SPI_MOSI_PU_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_PU, SPI_MISO_PU_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_PU, UART1_TXD_PU_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_PU, UART1_RXD_PU_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_PU, PCIE0_RESET_PU_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_PU, PCIE1_RESET_PU_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_PU, AN7583_MDC_0_PU_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_PU, AN7583_MDIO_0_PU_MASK), +}; + +static const struct airoha_pinctrl_conf en7581_pinctrl_pulldown_conf[] = { PINCTRL_CONF_DESC(0, REG_I2C_SDA_PD, UART1_TXD_PD_MASK), PINCTRL_CONF_DESC(1, REG_I2C_SDA_PD, UART1_RXD_PD_MASK), PINCTRL_CONF_DESC(2, REG_I2C_SDA_PD, I2C_SDA_PD_MASK), @@ -2103,7 +1944,63 @@ static const struct airoha_pinctrl_conf airoha_pinctrl_pulldown_conf[] = { PINCTRL_CONF_DESC(63, REG_I2C_SDA_PD, PCIE2_RESET_PD_MASK), }; -static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e2_conf[] = { +static const struct airoha_pinctrl_conf an7583_pinctrl_pulldown_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_PD, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_PD, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_PD, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_PD, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_PD, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_PD, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_PD, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_PD, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_PD, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_PD, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_PD, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PD, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PD, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PD, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PD, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PD, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PD, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PD, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PD, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PD, BIT(18)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PD, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PD, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PD, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PD, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PD, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PD, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PD, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PD, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PD, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PD, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PD, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PD, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_PD, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_PD, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_PD, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_PD, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_PD, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_PD, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_PD, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_PD, I2C_SCL_PD_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_PD, I2C_SDA_PD_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_PD, AN7583_I2C1_SCL_PD_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_PD, AN7583_I2C1_SDA_PD_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_PD, SPI_CLK_PD_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_PD, SPI_CS0_PD_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_PD, SPI_MOSI_PD_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_PD, SPI_MISO_PD_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_PD, UART1_TXD_PD_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_PD, UART1_RXD_PD_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_PD, PCIE0_RESET_PD_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_PD, PCIE1_RESET_PD_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_PD, AN7583_MDC_0_PD_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_PD, AN7583_MDIO_0_PD_MASK), +}; + +static const struct airoha_pinctrl_conf en7581_pinctrl_drive_e2_conf[] = { PINCTRL_CONF_DESC(0, REG_I2C_SDA_E2, UART1_TXD_E2_MASK), PINCTRL_CONF_DESC(1, REG_I2C_SDA_E2, UART1_RXD_E2_MASK), PINCTRL_CONF_DESC(2, REG_I2C_SDA_E2, I2C_SDA_E2_MASK), @@ -2164,7 +2061,63 @@ static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e2_conf[] = { PINCTRL_CONF_DESC(63, REG_I2C_SDA_E2, PCIE2_RESET_E2_MASK), }; -static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e4_conf[] = { +static const struct airoha_pinctrl_conf an7583_pinctrl_drive_e2_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_E2, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_E2, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_E2, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_E2, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_E2, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_E2, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_E2, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_E2, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_E2, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_E2, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_E2, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E2, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E2, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E2, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E2, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E2, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E2, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E2, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E2, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E2, BIT(18)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E2, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E2, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E2, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E2, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E2, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E2, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E2, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E2, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E2, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E2, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E2, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E2, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_E2, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_E2, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_E2, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_E2, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_E2, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_E2, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_E2, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_E2, I2C_SCL_E2_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_E2, I2C_SDA_E2_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_E2, AN7583_I2C1_SCL_E2_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_E2, AN7583_I2C1_SDA_E2_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_E2, SPI_CLK_E2_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_E2, SPI_CS0_E2_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_E2, SPI_MOSI_E2_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_E2, SPI_MISO_E2_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_E2, UART1_TXD_E2_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_E2, UART1_RXD_E2_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_E2, PCIE0_RESET_E2_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_E2, PCIE1_RESET_E2_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_E2, AN7583_MDC_0_E2_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_E2, AN7583_MDIO_0_E2_MASK), +}; + +static const struct airoha_pinctrl_conf en7581_pinctrl_drive_e4_conf[] = { PINCTRL_CONF_DESC(0, REG_I2C_SDA_E4, UART1_TXD_E4_MASK), PINCTRL_CONF_DESC(1, REG_I2C_SDA_E4, UART1_RXD_E4_MASK), PINCTRL_CONF_DESC(2, REG_I2C_SDA_E4, I2C_SDA_E4_MASK), @@ -2225,12 +2178,73 @@ static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e4_conf[] = { PINCTRL_CONF_DESC(63, REG_I2C_SDA_E4, PCIE2_RESET_E4_MASK), }; -static const struct airoha_pinctrl_conf airoha_pinctrl_pcie_rst_od_conf[] = { +static const struct airoha_pinctrl_conf an7583_pinctrl_drive_e4_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_E4, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_E4, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_E4, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_E4, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_E4, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_E4, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_E4, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_E4, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_E4, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_E4, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_E4, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E4, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E4, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E4, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E4, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E4, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E4, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E4, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E4, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E4, BIT(18)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E4, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E4, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E4, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E4, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E4, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E4, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E4, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E4, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E4, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E4, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E4, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E4, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_E4, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_E4, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_E4, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_E4, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_E4, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_E4, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_E4, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_E4, I2C_SCL_E4_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_E4, I2C_SDA_E4_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_E4, AN7583_I2C1_SCL_E4_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_E4, AN7583_I2C1_SDA_E4_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_E4, SPI_CLK_E4_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_E4, SPI_CS0_E4_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_E4, SPI_MOSI_E4_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_E4, SPI_MISO_E4_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_E4, UART1_TXD_E4_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_E4, UART1_RXD_E4_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_E4, PCIE0_RESET_E4_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_E4, PCIE1_RESET_E4_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_E4, AN7583_MDC_0_E4_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_E4, AN7583_MDIO_0_E4_MASK), +}; + +static const struct airoha_pinctrl_conf en7581_pinctrl_pcie_rst_od_conf[] = { PINCTRL_CONF_DESC(61, REG_PCIE_RESET_OD, PCIE0_RESET_OD_MASK), PINCTRL_CONF_DESC(62, REG_PCIE_RESET_OD, PCIE1_RESET_OD_MASK), PINCTRL_CONF_DESC(63, REG_PCIE_RESET_OD, PCIE2_RESET_OD_MASK), }; +static const struct airoha_pinctrl_conf an7583_pinctrl_pcie_rst_od_conf[] = { + PINCTRL_CONF_DESC(51, REG_PCIE_RESET_OD, PCIE0_RESET_OD_MASK), + PINCTRL_CONF_DESC(52, REG_PCIE_RESET_OD, PCIE1_RESET_OD_MASK), +}; + static int airoha_convert_pin_to_reg_offset(struct pinctrl_dev *pctrl_dev, struct pinctrl_gpio_range *range, int pin) @@ -2395,7 +2409,7 @@ static const struct irq_chip airoha_gpio_irq_chip = { }; static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl, - struct platform_device *pdev) + struct platform_device *pdev) { struct airoha_pinctrl_gpiochip *chip = &pinctrl->gpiochip; struct gpio_chip *gc = &chip->chip; @@ -2430,7 +2444,7 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl, return irq; err = devm_request_irq(dev, irq, airoha_irq_handler, IRQF_SHARED, - dev_name(dev), pinctrl); + dev_name(dev), pinctrl); if (err) { dev_err(dev, "error requesting irq %d: %d\n", irq, err); return err; @@ -2494,8 +2508,8 @@ static int airoha_pinmux_set_mux(struct pinctrl_dev *pctrl_dev, } static int airoha_pinmux_set_direction(struct pinctrl_dev *pctrl_dev, - struct pinctrl_gpio_range *range, - unsigned int p, bool input) + struct pinctrl_gpio_range *range, + unsigned int p, bool input) { struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); u32 mask, index; @@ -2546,12 +2560,17 @@ airoha_pinctrl_get_conf_reg(const struct airoha_pinctrl_conf *conf, } static int airoha_pinctrl_get_conf(struct airoha_pinctrl *pinctrl, - const struct airoha_pinctrl_conf *conf, - int conf_size, int pin, u32 *val) + enum airoha_pinctrl_confs_type conf_type, + int pin, u32 *val) { + const struct airoha_pinctrl_confs_info *confs_info; const struct airoha_pinctrl_reg *reg; - reg = airoha_pinctrl_get_conf_reg(conf, conf_size, pin); + confs_info = &pinctrl->confs_info[conf_type]; + + reg = airoha_pinctrl_get_conf_reg(confs_info->confs, + confs_info->num_confs, + pin); if (!reg) return -EINVAL; @@ -2564,62 +2583,57 @@ static int airoha_pinctrl_get_conf(struct airoha_pinctrl *pinctrl, } static int airoha_pinctrl_set_conf(struct airoha_pinctrl *pinctrl, - const struct airoha_pinctrl_conf *conf, - int conf_size, int pin, u32 val) + enum airoha_pinctrl_confs_type conf_type, + int pin, u32 val) { + const struct airoha_pinctrl_confs_info *confs_info; const struct airoha_pinctrl_reg *reg = NULL; - reg = airoha_pinctrl_get_conf_reg(conf, conf_size, pin); + confs_info = &pinctrl->confs_info[conf_type]; + + reg = airoha_pinctrl_get_conf_reg(confs_info->confs, + confs_info->num_confs, + pin); if (!reg) return -EINVAL; if (regmap_update_bits(pinctrl->chip_scu, reg->offset, reg->mask, - val << __ffs(reg->mask))) + val << __ffs(reg->mask))) return -EINVAL; return 0; } #define airoha_pinctrl_get_pullup_conf(pinctrl, pin, val) \ - airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pullup_conf, \ - ARRAY_SIZE(airoha_pinctrl_pullup_conf), \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLUP, \ (pin), (val)) #define airoha_pinctrl_get_pulldown_conf(pinctrl, pin, val) \ - airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pulldown_conf, \ - ARRAY_SIZE(airoha_pinctrl_pulldown_conf), \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLDOWN, \ (pin), (val)) #define airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, val) \ - airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_drive_e2_conf, \ - ARRAY_SIZE(airoha_pinctrl_drive_e2_conf), \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E2, \ (pin), (val)) #define airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, val) \ - airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_drive_e4_conf, \ - ARRAY_SIZE(airoha_pinctrl_drive_e4_conf), \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E4, \ (pin), (val)) #define airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, val) \ - airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pcie_rst_od_conf, \ - ARRAY_SIZE(airoha_pinctrl_pcie_rst_od_conf), \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_PCIE_RST_OD, \ (pin), (val)) #define airoha_pinctrl_set_pullup_conf(pinctrl, pin, val) \ - airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pullup_conf, \ - ARRAY_SIZE(airoha_pinctrl_pullup_conf), \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLUP, \ (pin), (val)) #define airoha_pinctrl_set_pulldown_conf(pinctrl, pin, val) \ - airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pulldown_conf, \ - ARRAY_SIZE(airoha_pinctrl_pulldown_conf), \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLDOWN, \ (pin), (val)) #define airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, val) \ - airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_drive_e2_conf, \ - ARRAY_SIZE(airoha_pinctrl_drive_e2_conf), \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E2, \ (pin), (val)) #define airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, val) \ - airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_drive_e4_conf, \ - ARRAY_SIZE(airoha_pinctrl_drive_e4_conf), \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E4, \ (pin), (val)) #define airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, val) \ - airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pcie_rst_od_conf, \ - ARRAY_SIZE(airoha_pinctrl_pcie_rst_od_conf), \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_PCIE_RST_OD, \ (pin), (val)) static int airoha_pinconf_get_direction(struct pinctrl_dev *pctrl_dev, u32 p) @@ -2796,13 +2810,14 @@ static int airoha_pinconf_set(struct pinctrl_dev *pctrl_dev, static int airoha_pinconf_group_get(struct pinctrl_dev *pctrl_dev, unsigned int group, unsigned long *config) { + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); u32 cur_config = 0; int i; - for (i = 0; i < airoha_pinctrl_groups[group].npins; i++) { + for (i = 0; i < pinctrl->grps[group].npins; i++) { if (airoha_pinconf_get(pctrl_dev, - airoha_pinctrl_groups[group].pins[i], - config)) + pinctrl->grps[group].pins[i], + config)) return -ENOTSUPP; if (i && cur_config != *config) @@ -2818,13 +2833,14 @@ static int airoha_pinconf_group_set(struct pinctrl_dev *pctrl_dev, unsigned int group, unsigned long *configs, unsigned int num_configs) { + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); int i; - for (i = 0; i < airoha_pinctrl_groups[group].npins; i++) { + for (i = 0; i < pinctrl->grps[group].npins; i++) { int err; err = airoha_pinconf_set(pctrl_dev, - airoha_pinctrl_groups[group].pins[i], + pinctrl->grps[group].pins[i], configs, num_configs); if (err) return err; @@ -2850,23 +2866,16 @@ static const struct pinctrl_ops airoha_pctlops = { .dt_free_map = pinconf_generic_dt_free_map, }; -static const struct pinctrl_desc airoha_pinctrl_desc = { - .name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .pctlops = &airoha_pctlops, - .pmxops = &airoha_pmxops, - .confops = &airoha_confops, - .pins = airoha_pinctrl_pins, - .npins = ARRAY_SIZE(airoha_pinctrl_pins), -}; - static int airoha_pinctrl_probe(struct platform_device *pdev) { + const struct airoha_pinctrl_match_data *data; struct device *dev = &pdev->dev; struct airoha_pinctrl *pinctrl; struct regmap *map; int err, i; + data = device_get_match_data(dev); + pinctrl = devm_kzalloc(dev, sizeof(*pinctrl), GFP_KERNEL); if (!pinctrl) return -ENOMEM; @@ -2881,14 +2890,23 @@ static int airoha_pinctrl_probe(struct platform_device *pdev) pinctrl->chip_scu = map; - err = devm_pinctrl_register_and_init(dev, &airoha_pinctrl_desc, + /* Init pinctrl desc struct */ + pinctrl->desc.name = KBUILD_MODNAME; + pinctrl->desc.owner = THIS_MODULE; + pinctrl->desc.pctlops = &airoha_pctlops; + pinctrl->desc.pmxops = &airoha_pmxops; + pinctrl->desc.confops = &airoha_confops; + pinctrl->desc.pins = data->pins; + pinctrl->desc.npins = data->num_pins; + + err = devm_pinctrl_register_and_init(dev, &pinctrl->desc, pinctrl, &pinctrl->ctrl); if (err) return err; /* build pin groups */ - for (i = 0; i < ARRAY_SIZE(airoha_pinctrl_groups); i++) { - const struct pingroup *grp = &airoha_pinctrl_groups[i]; + for (i = 0; i < data->num_grps; i++) { + const struct pingroup *grp = &data->grps[i]; err = pinctrl_generic_add_group(pinctrl->ctrl, grp->name, grp->pins, grp->npins, @@ -2901,10 +2919,10 @@ static int airoha_pinctrl_probe(struct platform_device *pdev) } /* build functions */ - for (i = 0; i < ARRAY_SIZE(airoha_pinctrl_funcs); i++) { + for (i = 0; i < data->num_funcs; i++) { const struct airoha_pinctrl_func *func; - func = &airoha_pinctrl_funcs[i]; + func = &data->funcs[i]; err = pinmux_generic_add_pinfunction(pinctrl->ctrl, &func->desc, (void *)func); @@ -2915,6 +2933,10 @@ static int airoha_pinctrl_probe(struct platform_device *pdev) } } + pinctrl->grps = data->grps; + pinctrl->funcs = data->funcs; + pinctrl->confs_info = data->confs_info; + err = pinctrl_enable(pinctrl->ctrl); if (err) return err; @@ -2923,8 +2945,71 @@ static int airoha_pinctrl_probe(struct platform_device *pdev) return airoha_pinctrl_add_gpiochip(pinctrl, pdev); } +static const struct airoha_pinctrl_match_data en7581_pinctrl_match_data = { + .pins = en7581_pinctrl_pins, + .num_pins = ARRAY_SIZE(en7581_pinctrl_pins), + .grps = en7581_pinctrl_groups, + .num_grps = ARRAY_SIZE(en7581_pinctrl_groups), + .funcs = en7581_pinctrl_funcs, + .num_funcs = ARRAY_SIZE(en7581_pinctrl_funcs), + .confs_info = { + [AIROHA_PINCTRL_CONFS_PULLUP] = { + .confs = en7581_pinctrl_pullup_conf, + .num_confs = ARRAY_SIZE(en7581_pinctrl_pullup_conf), + }, + [AIROHA_PINCTRL_CONFS_PULLDOWN] = { + .confs = en7581_pinctrl_pulldown_conf, + .num_confs = ARRAY_SIZE(en7581_pinctrl_pulldown_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E2] = { + .confs = en7581_pinctrl_drive_e2_conf, + .num_confs = ARRAY_SIZE(en7581_pinctrl_drive_e2_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E4] = { + .confs = en7581_pinctrl_drive_e4_conf, + .num_confs = ARRAY_SIZE(en7581_pinctrl_drive_e4_conf), + }, + [AIROHA_PINCTRL_CONFS_PCIE_RST_OD] = { + .confs = en7581_pinctrl_pcie_rst_od_conf, + .num_confs = ARRAY_SIZE(en7581_pinctrl_pcie_rst_od_conf), + }, + }, +}; + +static const struct airoha_pinctrl_match_data an7583_pinctrl_match_data = { + .pins = an7583_pinctrl_pins, + .num_pins = ARRAY_SIZE(an7583_pinctrl_pins), + .grps = an7583_pinctrl_groups, + .num_grps = ARRAY_SIZE(an7583_pinctrl_groups), + .funcs = an7583_pinctrl_funcs, + .num_funcs = ARRAY_SIZE(an7583_pinctrl_funcs), + .confs_info = { + [AIROHA_PINCTRL_CONFS_PULLUP] = { + .confs = an7583_pinctrl_pullup_conf, + .num_confs = ARRAY_SIZE(an7583_pinctrl_pullup_conf), + }, + [AIROHA_PINCTRL_CONFS_PULLDOWN] = { + .confs = an7583_pinctrl_pulldown_conf, + .num_confs = ARRAY_SIZE(an7583_pinctrl_pulldown_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E2] = { + .confs = an7583_pinctrl_drive_e2_conf, + .num_confs = ARRAY_SIZE(an7583_pinctrl_drive_e2_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E4] = { + .confs = an7583_pinctrl_drive_e4_conf, + .num_confs = ARRAY_SIZE(an7583_pinctrl_drive_e4_conf), + }, + [AIROHA_PINCTRL_CONFS_PCIE_RST_OD] = { + .confs = an7583_pinctrl_pcie_rst_od_conf, + .num_confs = ARRAY_SIZE(an7583_pinctrl_pcie_rst_od_conf), + }, + }, +}; + static const struct of_device_id airoha_pinctrl_of_match[] = { - { .compatible = "airoha,en7581-pinctrl" }, + { .compatible = "airoha,en7581-pinctrl", .data = &en7581_pinctrl_match_data }, + { .compatible = "airoha,an7583-pinctrl", .data = &an7583_pinctrl_match_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, airoha_pinctrl_of_match); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6878.c b/drivers/pinctrl/mediatek/pinctrl-mt6878.c new file mode 100644 index 000000000000..b59ae089128a --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt6878.c @@ -0,0 +1,1478 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 MediaTek Inc. + * Author: Light Hsieh <light.hsieh@mediatek.com> + * + * Copyright (C) 2025 Igor Belwon <igor.belwon@mentallysanemainliners.org> + */ + +#include <linux/module.h> +#include "pinctrl-mtk-mt6878.h" +#include "pinctrl-paris.h" + +/* MT6878 have multiple bases to program pin configuration listed as the below: + * GPIO_BASE: 0x10005000 + * IOCFG_BL_BASE: 0x11D10000 + * IOCFG_BM_BASE: 0x11D30000 + * IOCFG_BR_BASE: 0x11D40000 + * IOCFG_BL1_BASE: 0x11D50000 + * IOCFG_BR1_BASE: 0x11D60000 + * IOCFG_LM_BASE: 0x11E20000 + * IOCFG_LT_BASE: 0x11E30000 + * IOCFG_RM_BASE: 0x11EB0000 + * IOCFG_RT_BASE: 0x11EC0000 + * _i_based could be used to indicate what base the pin should be mapped into. + */ + +#define PIN_FIELD_BASE(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits) \ + PIN_FIELD_CALC(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits, \ + 32, 0) + +#define PINS_FIELD_BASE(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits) \ + PIN_FIELD_CALC(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits, \ + 32, 1) + +static const struct mtk_pin_field_calc mt6878_pin_mode_range[] = { + PIN_FIELD(0, 195, 0x300, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt6878_pin_dir_range[] = { + PIN_FIELD(0, 195, 0x0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_di_range[] = { + PIN_FIELD(0, 195, 0x200, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_do_range[] = { + PIN_FIELD(0, 195, 0x100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_ies_range[] = { + PIN_FIELD_BASE(0, 0, 3, 0x0070, 0x10, 9, 1), + PIN_FIELD_BASE(1, 1, 3, 0x0070, 0x10, 10, 1), + PIN_FIELD_BASE(2, 2, 3, 0x0070, 0x10, 11, 1), + PIN_FIELD_BASE(3, 3, 3, 0x0070, 0x10, 12, 1), + PIN_FIELD_BASE(4, 4, 3, 0x0070, 0x10, 13, 1), + PIN_FIELD_BASE(5, 5, 3, 0x0070, 0x10, 14, 1), + PIN_FIELD_BASE(6, 6, 4, 0x0050, 0x10, 13, 1), + PIN_FIELD_BASE(7, 7, 4, 0x0050, 0x10, 14, 1), + PIN_FIELD_BASE(8, 8, 4, 0x0050, 0x10, 15, 1), + PIN_FIELD_BASE(9, 9, 4, 0x0050, 0x10, 16, 1), + PIN_FIELD_BASE(10, 10, 4, 0x0050, 0x10, 10, 1), + PIN_FIELD_BASE(11, 11, 4, 0x0050, 0x10, 11, 1), + PIN_FIELD_BASE(12, 12, 4, 0x0050, 0x10, 12, 1), + PIN_FIELD_BASE(13, 13, 6, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(14, 14, 6, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(15, 15, 6, 0x0070, 0x10, 6, 1), + PIN_FIELD_BASE(16, 16, 6, 0x0070, 0x10, 7, 1), + PIN_FIELD_BASE(17, 17, 6, 0x0070, 0x10, 8, 1), + PIN_FIELD_BASE(18, 18, 6, 0x0070, 0x10, 9, 1), + PIN_FIELD_BASE(19, 19, 3, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(20, 20, 3, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(21, 21, 3, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(22, 22, 3, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(23, 23, 3, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(24, 24, 5, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(25, 25, 3, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(26, 26, 3, 0x0070, 0x10, 6, 1), + PIN_FIELD_BASE(27, 27, 3, 0x0070, 0x10, 7, 1), + PIN_FIELD_BASE(28, 28, 3, 0x0070, 0x10, 8, 1), + PIN_FIELD_BASE(29, 29, 6, 0x0070, 0x10, 10, 1), + PIN_FIELD_BASE(30, 30, 6, 0x0070, 0x10, 12, 1), + PIN_FIELD_BASE(31, 31, 6, 0x0070, 0x10, 13, 1), + PIN_FIELD_BASE(32, 32, 6, 0x0070, 0x10, 11, 1), + PIN_FIELD_BASE(33, 33, 9, 0x0050, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 9, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(35, 35, 9, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(36, 36, 8, 0x0090, 0x10, 0, 1), + PIN_FIELD_BASE(37, 37, 8, 0x0090, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 8, 0x0090, 0x10, 2, 1), + PIN_FIELD_BASE(39, 39, 8, 0x0090, 0x10, 3, 1), + PIN_FIELD_BASE(40, 40, 8, 0x0090, 0x10, 4, 1), + PIN_FIELD_BASE(41, 41, 4, 0x0050, 0x10, 20, 1), + PIN_FIELD_BASE(42, 42, 4, 0x0050, 0x10, 17, 1), + PIN_FIELD_BASE(43, 43, 4, 0x0050, 0x10, 19, 1), + PIN_FIELD_BASE(44, 44, 4, 0x0050, 0x10, 21, 1), + PIN_FIELD_BASE(45, 45, 4, 0x0050, 0x10, 18, 1), + PIN_FIELD_BASE(46, 46, 4, 0x0050, 0x10, 22, 1), + PIN_FIELD_BASE(47, 47, 4, 0x0050, 0x10, 23, 1), + PIN_FIELD_BASE(48, 48, 3, 0x0070, 0x10, 25, 1), + PIN_FIELD_BASE(49, 49, 3, 0x0070, 0x10, 23, 1), + PIN_FIELD_BASE(50, 50, 3, 0x0070, 0x10, 26, 1), + PIN_FIELD_BASE(51, 51, 3, 0x0070, 0x10, 24, 1), + PIN_FIELD_BASE(52, 52, 3, 0x0070, 0x10, 17, 1), + PIN_FIELD_BASE(53, 53, 3, 0x0070, 0x10, 18, 1), + PIN_FIELD_BASE(54, 54, 3, 0x0070, 0x10, 15, 1), + PIN_FIELD_BASE(55, 55, 3, 0x0070, 0x10, 16, 1), + PIN_FIELD_BASE(56, 56, 5, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(57, 57, 5, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(58, 58, 3, 0x0070, 0x10, 22, 1), + PIN_FIELD_BASE(59, 59, 3, 0x0070, 0x10, 21, 1), + PIN_FIELD_BASE(60, 60, 8, 0x0090, 0x10, 21, 1), + PIN_FIELD_BASE(61, 61, 8, 0x0090, 0x10, 22, 1), + PIN_FIELD_BASE(62, 62, 8, 0x0090, 0x10, 24, 1), + PIN_FIELD_BASE(63, 63, 8, 0x0090, 0x10, 23, 1), + PIN_FIELD_BASE(64, 64, 8, 0x0090, 0x10, 25, 1), + PIN_FIELD_BASE(65, 65, 8, 0x0090, 0x10, 26, 1), + PIN_FIELD_BASE(66, 66, 8, 0x0090, 0x10, 28, 1), + PIN_FIELD_BASE(67, 67, 8, 0x0090, 0x10, 27, 1), + PIN_FIELD_BASE(68, 68, 5, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(69, 69, 5, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(70, 70, 5, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(71, 71, 5, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(72, 72, 5, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(73, 73, 5, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(74, 74, 5, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(75, 75, 5, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(76, 76, 5, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(77, 77, 2, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 2, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(79, 79, 2, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(80, 80, 2, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(81, 81, 2, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(82, 82, 2, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(83, 83, 2, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(84, 84, 2, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(85, 85, 2, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(86, 86, 2, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(87, 87, 2, 0x0040, 0x10, 14, 1), + PIN_FIELD_BASE(88, 88, 2, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(89, 89, 4, 0x0050, 0x10, 9, 1), + PIN_FIELD_BASE(90, 90, 4, 0x0050, 0x10, 24, 1), + PIN_FIELD_BASE(91, 91, 4, 0x0050, 0x10, 8, 1), + PIN_FIELD_BASE(92, 92, 8, 0x0090, 0x10, 5, 1), + PIN_FIELD_BASE(93, 93, 8, 0x0090, 0x10, 6, 1), + PIN_FIELD_BASE(94, 94, 8, 0x0090, 0x10, 7, 1), + PIN_FIELD_BASE(95, 95, 8, 0x0090, 0x10, 8, 1), + PIN_FIELD_BASE(96, 96, 8, 0x0090, 0x10, 9, 1), + PIN_FIELD_BASE(97, 97, 1, 0x0070, 0x10, 19, 1), + PIN_FIELD_BASE(98, 98, 1, 0x0070, 0x10, 18, 1), + PIN_FIELD_BASE(99, 99, 1, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 1, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(101, 101, 1, 0x0070, 0x10, 10, 1), + PIN_FIELD_BASE(102, 102, 1, 0x0070, 0x10, 11, 1), + PIN_FIELD_BASE(103, 103, 1, 0x0070, 0x10, 12, 1), + PIN_FIELD_BASE(104, 104, 1, 0x0070, 0x10, 13, 1), + PIN_FIELD_BASE(105, 105, 1, 0x0070, 0x10, 14, 1), + PIN_FIELD_BASE(106, 106, 1, 0x0070, 0x10, 15, 1), + PIN_FIELD_BASE(107, 107, 1, 0x0070, 0x10, 16, 1), + PIN_FIELD_BASE(108, 108, 1, 0x0070, 0x10, 17, 1), + PIN_FIELD_BASE(109, 109, 1, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(110, 110, 1, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(111, 111, 1, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(112, 112, 1, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(113, 113, 1, 0x0070, 0x10, 6, 1), + PIN_FIELD_BASE(114, 114, 1, 0x0070, 0x10, 7, 1), + PIN_FIELD_BASE(115, 115, 1, 0x0070, 0x10, 8, 1), + PIN_FIELD_BASE(116, 116, 1, 0x0070, 0x10, 9, 1), + PIN_FIELD_BASE(117, 117, 1, 0x0070, 0x10, 20, 1), + PIN_FIELD_BASE(118, 118, 1, 0x0070, 0x10, 21, 1), + PIN_FIELD_BASE(119, 119, 1, 0x0070, 0x10, 22, 1), + PIN_FIELD_BASE(120, 120, 1, 0x0070, 0x10, 23, 1), + PIN_FIELD_BASE(121, 121, 1, 0x0070, 0x10, 24, 1), + PIN_FIELD_BASE(122, 122, 1, 0x0070, 0x10, 25, 1), + PIN_FIELD_BASE(123, 123, 1, 0x0070, 0x10, 26, 1), + PIN_FIELD_BASE(124, 124, 1, 0x0070, 0x10, 27, 1), + PIN_FIELD_BASE(125, 125, 8, 0x0090, 0x10, 20, 1), + PIN_FIELD_BASE(126, 126, 8, 0x0090, 0x10, 29, 1), + PIN_FIELD_BASE(127, 127, 8, 0x0090, 0x10, 30, 1), + PIN_FIELD_BASE(128, 128, 8, 0x0090, 0x10, 31, 1), + PIN_FIELD_BASE(129, 129, 8, 0x0090, 0x10, 10, 1), + PIN_FIELD_BASE(130, 130, 8, 0x0090, 0x10, 13, 1), + PIN_FIELD_BASE(131, 131, 6, 0x0070, 0x10, 14, 1), + PIN_FIELD_BASE(132, 132, 6, 0x0070, 0x10, 17, 1), + PIN_FIELD_BASE(133, 133, 8, 0x0090, 0x10, 11, 1), + PIN_FIELD_BASE(134, 134, 8, 0x0090, 0x10, 14, 1), + PIN_FIELD_BASE(135, 135, 6, 0x0070, 0x10, 15, 1), + PIN_FIELD_BASE(136, 136, 6, 0x0070, 0x10, 18, 1), + PIN_FIELD_BASE(137, 137, 6, 0x0070, 0x10, 16, 1), + PIN_FIELD_BASE(138, 138, 6, 0x0070, 0x10, 19, 1), + PIN_FIELD_BASE(139, 139, 6, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(140, 140, 6, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(141, 141, 6, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(142, 142, 6, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(143, 143, 8, 0x0090, 0x10, 12, 1), + PIN_FIELD_BASE(144, 144, 8, 0x0090, 0x10, 15, 1), + PIN_FIELD_BASE(145, 145, 5, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(146, 146, 5, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(147, 147, 3, 0x0070, 0x10, 19, 1), + PIN_FIELD_BASE(148, 148, 3, 0x0070, 0x10, 20, 1), + PIN_FIELD_BASE(149, 149, 8, 0x0090, 0x10, 16, 1), + PIN_FIELD_BASE(150, 150, 8, 0x0090, 0x10, 17, 1), + PIN_FIELD_BASE(151, 151, 8, 0x0090, 0x10, 18, 1), + PIN_FIELD_BASE(152, 152, 8, 0x0090, 0x10, 19, 1), + PIN_FIELD_BASE(153, 153, 2, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(154, 154, 2, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(155, 155, 2, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(156, 156, 9, 0x0050, 0x10, 15, 1), + PIN_FIELD_BASE(157, 157, 9, 0x0050, 0x10, 16, 1), + PIN_FIELD_BASE(158, 158, 9, 0x0050, 0x10, 17, 1), + PIN_FIELD_BASE(159, 159, 9, 0x0050, 0x10, 18, 1), + PIN_FIELD_BASE(160, 160, 4, 0x0050, 0x10, 26, 1), + PIN_FIELD_BASE(161, 161, 4, 0x0050, 0x10, 25, 1), + PIN_FIELD_BASE(162, 162, 4, 0x0050, 0x10, 28, 1), + PIN_FIELD_BASE(163, 163, 4, 0x0050, 0x10, 27, 1), + PIN_FIELD_BASE(164, 164, 4, 0x0050, 0x10, 0, 1), + PIN_FIELD_BASE(165, 165, 4, 0x0050, 0x10, 7, 1), + PIN_FIELD_BASE(166, 166, 4, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(167, 167, 4, 0x0050, 0x10, 4, 1), + PIN_FIELD_BASE(168, 168, 4, 0x0050, 0x10, 5, 1), + PIN_FIELD_BASE(169, 169, 4, 0x0050, 0x10, 6, 1), + PIN_FIELD_BASE(170, 170, 4, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(171, 171, 4, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(172, 172, 9, 0x0050, 0x10, 7, 1), + PIN_FIELD_BASE(173, 173, 9, 0x0050, 0x10, 8, 1), + PIN_FIELD_BASE(174, 174, 9, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(175, 175, 9, 0x0050, 0x10, 4, 1), + PIN_FIELD_BASE(176, 176, 9, 0x0050, 0x10, 5, 1), + PIN_FIELD_BASE(177, 177, 9, 0x0050, 0x10, 9, 1), + PIN_FIELD_BASE(178, 178, 9, 0x0050, 0x10, 10, 1), + PIN_FIELD_BASE(179, 179, 9, 0x0050, 0x10, 11, 1), + PIN_FIELD_BASE(180, 180, 9, 0x0050, 0x10, 12, 1), + PIN_FIELD_BASE(181, 181, 9, 0x0050, 0x10, 13, 1), + PIN_FIELD_BASE(182, 182, 9, 0x0050, 0x10, 14, 1), + PIN_FIELD_BASE(183, 183, 9, 0x0050, 0x10, 6, 1), + PIN_FIELD_BASE(184, 184, 7, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(185, 185, 7, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(186, 186, 7, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(187, 187, 7, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(188, 188, 7, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(189, 189, 7, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(190, 190, 7, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(191, 191, 7, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(192, 192, 7, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(193, 193, 7, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(194, 194, 7, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(195, 195, 7, 0x0040, 0x10, 9, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_smt_range[] = { + PIN_FIELD_BASE(0, 0, 3, 0x00e0, 0x10, 16, 1), + PIN_FIELD_BASE(1, 1, 3, 0x00e0, 0x10, 16, 1), + PIN_FIELD_BASE(2, 2, 3, 0x00e0, 0x10, 15, 1), + PIN_FIELD_BASE(3, 3, 3, 0x00e0, 0x10, 15, 1), + PIN_FIELD_BASE(4, 4, 3, 0x00e0, 0x10, 9, 1), + PIN_FIELD_BASE(5, 5, 3, 0x00e0, 0x10, 10, 1), + PIN_FIELD_BASE(6, 6, 4, 0x00b0, 0x10, 2, 1), + PIN_FIELD_BASE(7, 7, 4, 0x00b0, 0x10, 3, 1), + PIN_FIELD_BASE(8, 8, 4, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(9, 9, 4, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(10, 10, 4, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(11, 11, 4, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(12, 12, 4, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(13, 13, 6, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(14, 14, 6, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(15, 15, 6, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(16, 16, 6, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(17, 17, 6, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(18, 18, 6, 0x00e0, 0x10, 7, 1), + PIN_FIELD_BASE(19, 19, 3, 0x00e0, 0x10, 0, 1), + PIN_FIELD_BASE(20, 20, 3, 0x00e0, 0x10, 1, 1), + PIN_FIELD_BASE(21, 21, 3, 0x00e0, 0x10, 2, 1), + PIN_FIELD_BASE(22, 22, 3, 0x00e0, 0x10, 3, 1), + PIN_FIELD_BASE(23, 23, 3, 0x00e0, 0x10, 4, 1), + PIN_FIELD_BASE(24, 24, 5, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(25, 25, 3, 0x00e0, 0x10, 5, 1), + PIN_FIELD_BASE(26, 26, 3, 0x00e0, 0x10, 6, 1), + PIN_FIELD_BASE(27, 27, 3, 0x00e0, 0x10, 7, 1), + PIN_FIELD_BASE(28, 28, 3, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(29, 29, 6, 0x00e0, 0x10, 4, 1), + PIN_FIELD_BASE(30, 30, 6, 0x00e0, 0x10, 9, 1), + PIN_FIELD_BASE(31, 31, 6, 0x00e0, 0x10, 6, 1), + PIN_FIELD_BASE(32, 32, 6, 0x00e0, 0x10, 5, 1), + PIN_FIELD_BASE(33, 33, 9, 0x00f0, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 9, 0x00f0, 0x10, 1, 1), + PIN_FIELD_BASE(35, 35, 9, 0x00f0, 0x10, 2, 1), + PIN_FIELD_BASE(36, 36, 8, 0x0130, 0x10, 0, 1), + PIN_FIELD_BASE(37, 37, 8, 0x0130, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 8, 0x0130, 0x10, 2, 1), + PIN_FIELD_BASE(39, 39, 8, 0x0130, 0x10, 3, 1), + PIN_FIELD_BASE(40, 40, 8, 0x0130, 0x10, 4, 1), + PIN_FIELD_BASE(41, 41, 4, 0x00b0, 0x10, 7, 1), + PIN_FIELD_BASE(42, 42, 4, 0x00b0, 0x10, 4, 1), + PIN_FIELD_BASE(43, 43, 4, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(44, 44, 4, 0x00b0, 0x10, 8, 1), + PIN_FIELD_BASE(45, 45, 4, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(46, 46, 4, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(47, 47, 4, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(48, 48, 3, 0x00e0, 0x10, 16, 1), + PIN_FIELD_BASE(49, 49, 3, 0x00e0, 0x10, 16, 1), + PIN_FIELD_BASE(50, 50, 3, 0x00e0, 0x10, 14, 1), + PIN_FIELD_BASE(51, 51, 3, 0x00e0, 0x10, 14, 1), + PIN_FIELD_BASE(52, 52, 3, 0x00e0, 0x10, 12, 1), + PIN_FIELD_BASE(53, 53, 3, 0x00e0, 0x10, 13, 1), + PIN_FIELD_BASE(54, 54, 3, 0x00e0, 0x10, 17, 1), + PIN_FIELD_BASE(55, 55, 3, 0x00e0, 0x10, 11, 1), + PIN_FIELD_BASE(56, 56, 5, 0x00b0, 0x10, 8, 1), + PIN_FIELD_BASE(57, 57, 5, 0x00b0, 0x10, 9, 1), + PIN_FIELD_BASE(58, 58, 3, 0x00e0, 0x10, 21, 1), + PIN_FIELD_BASE(59, 59, 3, 0x00e0, 0x10, 20, 1), + PIN_FIELD_BASE(60, 60, 8, 0x0130, 0x10, 20, 1), + PIN_FIELD_BASE(61, 61, 8, 0x0130, 0x10, 21, 1), + PIN_FIELD_BASE(62, 62, 8, 0x0130, 0x10, 23, 1), + PIN_FIELD_BASE(63, 63, 8, 0x0130, 0x10, 22, 1), + PIN_FIELD_BASE(64, 64, 8, 0x0130, 0x10, 24, 1), + PIN_FIELD_BASE(65, 65, 8, 0x0130, 0x10, 25, 1), + PIN_FIELD_BASE(66, 66, 8, 0x0130, 0x10, 27, 1), + PIN_FIELD_BASE(67, 67, 8, 0x0130, 0x10, 26, 1), + PIN_FIELD_BASE(68, 68, 5, 0x00b0, 0x10, 3, 1), + PIN_FIELD_BASE(69, 69, 5, 0x00b0, 0x10, 4, 1), + PIN_FIELD_BASE(70, 70, 5, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(71, 71, 5, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(72, 72, 5, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(73, 73, 5, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(74, 74, 5, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(75, 75, 5, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(76, 76, 5, 0x00b0, 0x10, 1, 1), + PIN_FIELD_BASE(77, 77, 2, 0x00e0, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 2, 0x00e0, 0x10, 1, 1), + PIN_FIELD_BASE(79, 79, 2, 0x00e0, 0x10, 2, 1), + PIN_FIELD_BASE(80, 80, 2, 0x00e0, 0x10, 3, 1), + PIN_FIELD_BASE(81, 81, 2, 0x00e0, 0x10, 4, 1), + PIN_FIELD_BASE(82, 82, 2, 0x00e0, 0x10, 5, 1), + PIN_FIELD_BASE(83, 83, 2, 0x00e0, 0x10, 6, 1), + PIN_FIELD_BASE(84, 84, 2, 0x00e0, 0x10, 9, 1), + PIN_FIELD_BASE(85, 85, 2, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(86, 86, 2, 0x00e0, 0x10, 10, 1), + PIN_FIELD_BASE(87, 87, 2, 0x00e0, 0x10, 12, 1), + PIN_FIELD_BASE(88, 88, 2, 0x00e0, 0x10, 11, 1), + PIN_FIELD_BASE(89, 89, 4, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(90, 90, 4, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(91, 91, 4, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(92, 92, 8, 0x0130, 0x10, 5, 1), + PIN_FIELD_BASE(93, 93, 8, 0x0130, 0x10, 6, 1), + PIN_FIELD_BASE(94, 94, 8, 0x0130, 0x10, 7, 1), + PIN_FIELD_BASE(95, 95, 8, 0x0130, 0x10, 8, 1), + PIN_FIELD_BASE(96, 96, 8, 0x0130, 0x10, 9, 1), + PIN_FIELD_BASE(97, 97, 1, 0x0120, 0x10, 25, 1), + PIN_FIELD_BASE(98, 98, 1, 0x0120, 0x10, 25, 1), + PIN_FIELD_BASE(99, 99, 1, 0x0120, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 1, 0x0120, 0x10, 1, 1), + PIN_FIELD_BASE(101, 101, 1, 0x0120, 0x10, 10, 1), + PIN_FIELD_BASE(102, 102, 1, 0x0120, 0x10, 11, 1), + PIN_FIELD_BASE(103, 103, 1, 0x0120, 0x10, 12, 1), + PIN_FIELD_BASE(104, 104, 1, 0x0120, 0x10, 13, 1), + PIN_FIELD_BASE(105, 105, 1, 0x0120, 0x10, 14, 1), + PIN_FIELD_BASE(106, 106, 1, 0x0120, 0x10, 15, 1), + PIN_FIELD_BASE(107, 107, 1, 0x0120, 0x10, 16, 1), + PIN_FIELD_BASE(108, 108, 1, 0x0120, 0x10, 17, 1), + PIN_FIELD_BASE(109, 109, 1, 0x0120, 0x10, 2, 1), + PIN_FIELD_BASE(110, 110, 1, 0x0120, 0x10, 3, 1), + PIN_FIELD_BASE(111, 111, 1, 0x0120, 0x10, 4, 1), + PIN_FIELD_BASE(112, 112, 1, 0x0120, 0x10, 5, 1), + PIN_FIELD_BASE(113, 113, 1, 0x0120, 0x10, 6, 1), + PIN_FIELD_BASE(114, 114, 1, 0x0120, 0x10, 7, 1), + PIN_FIELD_BASE(115, 115, 1, 0x0120, 0x10, 8, 1), + PIN_FIELD_BASE(116, 116, 1, 0x0120, 0x10, 9, 1), + PIN_FIELD_BASE(117, 117, 1, 0x0120, 0x10, 18, 1), + PIN_FIELD_BASE(118, 118, 1, 0x0120, 0x10, 19, 1), + PIN_FIELD_BASE(119, 119, 1, 0x0120, 0x10, 20, 1), + PIN_FIELD_BASE(120, 120, 1, 0x0120, 0x10, 21, 1), + PIN_FIELD_BASE(121, 121, 1, 0x0120, 0x10, 22, 1), + PIN_FIELD_BASE(122, 122, 1, 0x0120, 0x10, 23, 1), + PIN_FIELD_BASE(123, 123, 1, 0x0120, 0x10, 24, 1), + PIN_FIELD_BASE(124, 124, 1, 0x0120, 0x10, 24, 1), + PIN_FIELD_BASE(125, 125, 8, 0x0130, 0x10, 19, 1), + PIN_FIELD_BASE(126, 126, 8, 0x0130, 0x10, 28, 1), + PIN_FIELD_BASE(127, 127, 8, 0x0130, 0x10, 29, 1), + PIN_FIELD_BASE(128, 128, 8, 0x0130, 0x10, 30, 1), + PIN_FIELD_BASE(129, 129, 8, 0x0130, 0x10, 10, 1), + PIN_FIELD_BASE(130, 130, 8, 0x0130, 0x10, 13, 1), + PIN_FIELD_BASE(131, 131, 6, 0x00e0, 0x10, 10, 1), + PIN_FIELD_BASE(132, 132, 6, 0x00e0, 0x10, 13, 1), + PIN_FIELD_BASE(133, 133, 8, 0x0130, 0x10, 11, 1), + PIN_FIELD_BASE(134, 134, 8, 0x0130, 0x10, 14, 1), + PIN_FIELD_BASE(135, 135, 6, 0x00e0, 0x10, 11, 1), + PIN_FIELD_BASE(136, 136, 6, 0x00e0, 0x10, 14, 1), + PIN_FIELD_BASE(137, 137, 6, 0x00e0, 0x10, 12, 1), + PIN_FIELD_BASE(138, 138, 6, 0x00e0, 0x10, 15, 1), + PIN_FIELD_BASE(139, 139, 6, 0x00e0, 0x10, 0, 1), + PIN_FIELD_BASE(140, 140, 6, 0x00e0, 0x10, 2, 1), + PIN_FIELD_BASE(141, 141, 6, 0x00e0, 0x10, 1, 1), + PIN_FIELD_BASE(142, 142, 6, 0x00e0, 0x10, 3, 1), + PIN_FIELD_BASE(143, 143, 8, 0x0130, 0x10, 12, 1), + PIN_FIELD_BASE(144, 144, 8, 0x0130, 0x10, 15, 1), + PIN_FIELD_BASE(145, 145, 5, 0x00b0, 0x10, 2, 1), + PIN_FIELD_BASE(146, 146, 5, 0x00b0, 0x10, 7, 1), + PIN_FIELD_BASE(147, 147, 3, 0x00e0, 0x10, 18, 1), + PIN_FIELD_BASE(148, 148, 3, 0x00e0, 0x10, 19, 1), + PIN_FIELD_BASE(149, 149, 8, 0x0130, 0x10, 16, 1), + PIN_FIELD_BASE(150, 150, 8, 0x0130, 0x10, 17, 1), + PIN_FIELD_BASE(151, 151, 8, 0x0130, 0x10, 18, 1), + PIN_FIELD_BASE(152, 152, 8, 0x0130, 0x10, 18, 1), + PIN_FIELD_BASE(153, 153, 2, 0x00e0, 0x10, 7, 1), + PIN_FIELD_BASE(154, 154, 2, 0x00e0, 0x10, 7, 1), + PIN_FIELD_BASE(155, 155, 2, 0x00e0, 0x10, 7, 1), + PIN_FIELD_BASE(156, 156, 9, 0x00f0, 0x10, 7, 1), + PIN_FIELD_BASE(157, 157, 9, 0x00f0, 0x10, 8, 1), + PIN_FIELD_BASE(158, 158, 9, 0x00f0, 0x10, 9, 1), + PIN_FIELD_BASE(159, 159, 9, 0x00f0, 0x10, 10, 1), + PIN_FIELD_BASE(160, 160, 4, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(161, 161, 4, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(162, 162, 4, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(163, 163, 4, 0x00b0, 0x10, 9, 1), + PIN_FIELD_BASE(164, 164, 4, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(165, 165, 4, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(166, 166, 4, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(167, 167, 4, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(168, 168, 4, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(169, 169, 4, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(170, 170, 4, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(171, 171, 4, 0x00b0, 0x10, 1, 1), + PIN_FIELD_BASE(172, 172, 9, 0x00f0, 0x10, 5, 1), + PIN_FIELD_BASE(173, 173, 9, 0x00f0, 0x10, 5, 1), + PIN_FIELD_BASE(174, 174, 9, 0x00f0, 0x10, 5, 1), + PIN_FIELD_BASE(175, 175, 9, 0x00f0, 0x10, 5, 1), + PIN_FIELD_BASE(176, 176, 9, 0x00f0, 0x10, 5, 1), + PIN_FIELD_BASE(177, 177, 9, 0x00f0, 0x10, 5, 1), + PIN_FIELD_BASE(178, 178, 9, 0x00f0, 0x10, 6, 1), + PIN_FIELD_BASE(179, 179, 9, 0x00f0, 0x10, 6, 1), + PIN_FIELD_BASE(180, 180, 9, 0x00f0, 0x10, 6, 1), + PIN_FIELD_BASE(181, 181, 9, 0x00f0, 0x10, 3, 1), + PIN_FIELD_BASE(182, 182, 9, 0x00f0, 0x10, 4, 1), + PIN_FIELD_BASE(183, 183, 9, 0x00f0, 0x10, 5, 1), + PIN_FIELD_BASE(184, 184, 7, 0x00d0, 0x10, 10, 1), + PIN_FIELD_BASE(185, 185, 7, 0x00d0, 0x10, 0, 1), + PIN_FIELD_BASE(186, 186, 7, 0x00d0, 0x10, 1, 1), + PIN_FIELD_BASE(187, 187, 7, 0x00d0, 0x10, 11, 1), + PIN_FIELD_BASE(188, 188, 7, 0x00d0, 0x10, 2, 1), + PIN_FIELD_BASE(189, 189, 7, 0x00d0, 0x10, 3, 1), + PIN_FIELD_BASE(190, 190, 7, 0x00d0, 0x10, 4, 1), + PIN_FIELD_BASE(191, 191, 7, 0x00d0, 0x10, 5, 1), + PIN_FIELD_BASE(192, 192, 7, 0x00d0, 0x10, 6, 1), + PIN_FIELD_BASE(193, 193, 7, 0x00d0, 0x10, 7, 1), + PIN_FIELD_BASE(194, 194, 7, 0x00d0, 0x10, 8, 1), + PIN_FIELD_BASE(195, 195, 7, 0x00d0, 0x10, 9, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_pu_range[] = { + PIN_FIELD_BASE(0, 0, 3, 0x00b0, 0x10, 9, 1), + PIN_FIELD_BASE(1, 1, 3, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(2, 2, 3, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(3, 3, 3, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(4, 4, 3, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(5, 5, 3, 0x00b0, 0x10, 14, 1), + PIN_FIELD_BASE(6, 6, 4, 0x0090, 0x10, 13, 1), + PIN_FIELD_BASE(7, 7, 4, 0x0090, 0x10, 14, 1), + PIN_FIELD_BASE(8, 8, 4, 0x0090, 0x10, 15, 1), + PIN_FIELD_BASE(9, 9, 4, 0x0090, 0x10, 16, 1), + PIN_FIELD_BASE(10, 10, 4, 0x0090, 0x10, 10, 1), + PIN_FIELD_BASE(11, 11, 4, 0x0090, 0x10, 11, 1), + PIN_FIELD_BASE(12, 12, 4, 0x0090, 0x10, 12, 1), + PIN_FIELD_BASE(13, 13, 6, 0x00b0, 0x10, 4, 1), + PIN_FIELD_BASE(14, 14, 6, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(15, 15, 6, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(16, 16, 6, 0x00b0, 0x10, 7, 1), + PIN_FIELD_BASE(17, 17, 6, 0x00b0, 0x10, 8, 1), + PIN_FIELD_BASE(18, 18, 6, 0x00b0, 0x10, 9, 1), + PIN_FIELD_BASE(19, 19, 3, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(20, 20, 3, 0x00b0, 0x10, 1, 1), + PIN_FIELD_BASE(21, 21, 3, 0x00b0, 0x10, 2, 1), + PIN_FIELD_BASE(22, 22, 3, 0x00b0, 0x10, 3, 1), + PIN_FIELD_BASE(23, 23, 3, 0x00b0, 0x10, 4, 1), + PIN_FIELD_BASE(24, 24, 5, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(25, 25, 3, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(26, 26, 3, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(27, 27, 3, 0x00b0, 0x10, 7, 1), + PIN_FIELD_BASE(28, 28, 3, 0x00b0, 0x10, 8, 1), + PIN_FIELD_BASE(29, 29, 6, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(30, 30, 6, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(31, 31, 6, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(32, 32, 6, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(36, 36, 8, 0x00d0, 0x10, 0, 1), + PIN_FIELD_BASE(37, 37, 8, 0x00d0, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 8, 0x00d0, 0x10, 2, 1), + PIN_FIELD_BASE(39, 39, 8, 0x00d0, 0x10, 3, 1), + PIN_FIELD_BASE(40, 40, 8, 0x00d0, 0x10, 4, 1), + PIN_FIELD_BASE(41, 41, 4, 0x0090, 0x10, 20, 1), + PIN_FIELD_BASE(42, 42, 4, 0x0090, 0x10, 17, 1), + PIN_FIELD_BASE(43, 43, 4, 0x0090, 0x10, 19, 1), + PIN_FIELD_BASE(44, 44, 4, 0x0090, 0x10, 21, 1), + PIN_FIELD_BASE(45, 45, 4, 0x0090, 0x10, 18, 1), + PIN_FIELD_BASE(46, 46, 4, 0x0090, 0x10, 22, 1), + PIN_FIELD_BASE(47, 47, 4, 0x0090, 0x10, 23, 1), + PIN_FIELD_BASE(48, 48, 3, 0x00b0, 0x10, 25, 1), + PIN_FIELD_BASE(49, 49, 3, 0x00b0, 0x10, 23, 1), + PIN_FIELD_BASE(50, 50, 3, 0x00b0, 0x10, 26, 1), + PIN_FIELD_BASE(51, 51, 3, 0x00b0, 0x10, 24, 1), + PIN_FIELD_BASE(52, 52, 3, 0x00b0, 0x10, 17, 1), + PIN_FIELD_BASE(53, 53, 3, 0x00b0, 0x10, 18, 1), + PIN_FIELD_BASE(54, 54, 3, 0x00b0, 0x10, 15, 1), + PIN_FIELD_BASE(55, 55, 3, 0x00b0, 0x10, 16, 1), + PIN_FIELD_BASE(56, 56, 5, 0x0080, 0x10, 8, 1), + PIN_FIELD_BASE(57, 57, 5, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(58, 58, 3, 0x00b0, 0x10, 22, 1), + PIN_FIELD_BASE(59, 59, 3, 0x00b0, 0x10, 21, 1), + PIN_FIELD_BASE(60, 60, 8, 0x00d0, 0x10, 21, 1), + PIN_FIELD_BASE(61, 61, 8, 0x00d0, 0x10, 22, 1), + PIN_FIELD_BASE(62, 62, 8, 0x00d0, 0x10, 24, 1), + PIN_FIELD_BASE(63, 63, 8, 0x00d0, 0x10, 23, 1), + PIN_FIELD_BASE(64, 64, 8, 0x00d0, 0x10, 25, 1), + PIN_FIELD_BASE(65, 65, 8, 0x00d0, 0x10, 26, 1), + PIN_FIELD_BASE(66, 66, 8, 0x00d0, 0x10, 28, 1), + PIN_FIELD_BASE(67, 67, 8, 0x00d0, 0x10, 27, 1), + PIN_FIELD_BASE(68, 68, 5, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(69, 69, 5, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(70, 70, 5, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(71, 71, 5, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(72, 72, 5, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(73, 73, 5, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(74, 74, 5, 0x0080, 0x10, 13, 1), + PIN_FIELD_BASE(75, 75, 5, 0x0080, 0x10, 12, 1), + PIN_FIELD_BASE(76, 76, 5, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(89, 89, 4, 0x0090, 0x10, 9, 1), + PIN_FIELD_BASE(90, 90, 4, 0x0090, 0x10, 24, 1), + PIN_FIELD_BASE(91, 91, 4, 0x0090, 0x10, 8, 1), + PIN_FIELD_BASE(92, 92, 8, 0x00d0, 0x10, 5, 1), + PIN_FIELD_BASE(93, 93, 8, 0x00d0, 0x10, 6, 1), + PIN_FIELD_BASE(94, 94, 8, 0x00d0, 0x10, 7, 1), + PIN_FIELD_BASE(95, 95, 8, 0x00d0, 0x10, 8, 1), + PIN_FIELD_BASE(96, 96, 8, 0x00d0, 0x10, 9, 1), + PIN_FIELD_BASE(99, 99, 1, 0x00c0, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 1, 0x00c0, 0x10, 1, 1), + PIN_FIELD_BASE(101, 101, 1, 0x00c0, 0x10, 10, 1), + PIN_FIELD_BASE(102, 102, 1, 0x00c0, 0x10, 11, 1), + PIN_FIELD_BASE(103, 103, 1, 0x00c0, 0x10, 12, 1), + PIN_FIELD_BASE(104, 104, 1, 0x00c0, 0x10, 13, 1), + PIN_FIELD_BASE(105, 105, 1, 0x00c0, 0x10, 14, 1), + PIN_FIELD_BASE(106, 106, 1, 0x00c0, 0x10, 15, 1), + PIN_FIELD_BASE(107, 107, 1, 0x00c0, 0x10, 16, 1), + PIN_FIELD_BASE(108, 108, 1, 0x00c0, 0x10, 17, 1), + PIN_FIELD_BASE(109, 109, 1, 0x00c0, 0x10, 2, 1), + PIN_FIELD_BASE(110, 110, 1, 0x00c0, 0x10, 3, 1), + PIN_FIELD_BASE(111, 111, 1, 0x00c0, 0x10, 4, 1), + PIN_FIELD_BASE(112, 112, 1, 0x00c0, 0x10, 5, 1), + PIN_FIELD_BASE(113, 113, 1, 0x00c0, 0x10, 6, 1), + PIN_FIELD_BASE(114, 114, 1, 0x00c0, 0x10, 7, 1), + PIN_FIELD_BASE(115, 115, 1, 0x00c0, 0x10, 8, 1), + PIN_FIELD_BASE(116, 116, 1, 0x00c0, 0x10, 9, 1), + PIN_FIELD_BASE(125, 125, 8, 0x00d0, 0x10, 20, 1), + PIN_FIELD_BASE(126, 126, 8, 0x00d0, 0x10, 29, 1), + PIN_FIELD_BASE(127, 127, 8, 0x00d0, 0x10, 30, 1), + PIN_FIELD_BASE(128, 128, 8, 0x00d0, 0x10, 31, 1), + PIN_FIELD_BASE(129, 129, 8, 0x00d0, 0x10, 10, 1), + PIN_FIELD_BASE(130, 130, 8, 0x00d0, 0x10, 13, 1), + PIN_FIELD_BASE(131, 131, 6, 0x00b0, 0x10, 14, 1), + PIN_FIELD_BASE(132, 132, 6, 0x00b0, 0x10, 17, 1), + PIN_FIELD_BASE(133, 133, 8, 0x00d0, 0x10, 11, 1), + PIN_FIELD_BASE(134, 134, 8, 0x00d0, 0x10, 14, 1), + PIN_FIELD_BASE(135, 135, 6, 0x00b0, 0x10, 15, 1), + PIN_FIELD_BASE(136, 136, 6, 0x00b0, 0x10, 18, 1), + PIN_FIELD_BASE(137, 137, 6, 0x00b0, 0x10, 16, 1), + PIN_FIELD_BASE(138, 138, 6, 0x00b0, 0x10, 19, 1), + PIN_FIELD_BASE(139, 139, 6, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(140, 140, 6, 0x00b0, 0x10, 2, 1), + PIN_FIELD_BASE(141, 141, 6, 0x00b0, 0x10, 1, 1), + PIN_FIELD_BASE(142, 142, 6, 0x00b0, 0x10, 3, 1), + PIN_FIELD_BASE(143, 143, 8, 0x00d0, 0x10, 12, 1), + PIN_FIELD_BASE(144, 144, 8, 0x00d0, 0x10, 15, 1), + PIN_FIELD_BASE(145, 145, 5, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(146, 146, 5, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(147, 147, 3, 0x00b0, 0x10, 19, 1), + PIN_FIELD_BASE(148, 148, 3, 0x00b0, 0x10, 20, 1), + PIN_FIELD_BASE(149, 149, 8, 0x00d0, 0x10, 16, 1), + PIN_FIELD_BASE(150, 150, 8, 0x00d0, 0x10, 17, 1), + PIN_FIELD_BASE(151, 151, 8, 0x00d0, 0x10, 18, 1), + PIN_FIELD_BASE(152, 152, 8, 0x00d0, 0x10, 19, 1), + PIN_FIELD_BASE(156, 156, 9, 0x00a0, 0x10, 0, 1), + PIN_FIELD_BASE(157, 157, 9, 0x00a0, 0x10, 1, 1), + PIN_FIELD_BASE(158, 158, 9, 0x00a0, 0x10, 2, 1), + PIN_FIELD_BASE(159, 159, 9, 0x00a0, 0x10, 3, 1), + PIN_FIELD_BASE(160, 160, 4, 0x0090, 0x10, 26, 1), + PIN_FIELD_BASE(161, 161, 4, 0x0090, 0x10, 25, 1), + PIN_FIELD_BASE(162, 162, 4, 0x0090, 0x10, 30, 1), + PIN_FIELD_BASE(163, 163, 4, 0x0090, 0x10, 29, 1), + PIN_FIELD_BASE(164, 164, 4, 0x0090, 0x10, 0, 1), + PIN_FIELD_BASE(165, 165, 4, 0x0090, 0x10, 7, 1), + PIN_FIELD_BASE(166, 166, 4, 0x0090, 0x10, 3, 1), + PIN_FIELD_BASE(167, 167, 4, 0x0090, 0x10, 4, 1), + PIN_FIELD_BASE(168, 168, 4, 0x0090, 0x10, 5, 1), + PIN_FIELD_BASE(169, 169, 4, 0x0090, 0x10, 6, 1), + PIN_FIELD_BASE(170, 170, 4, 0x0090, 0x10, 1, 1), + PIN_FIELD_BASE(171, 171, 4, 0x0090, 0x10, 2, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_pd_range[] = { + PIN_FIELD_BASE(0, 0, 3, 0x00a0, 0x10, 9, 1), + PIN_FIELD_BASE(1, 1, 3, 0x00a0, 0x10, 10, 1), + PIN_FIELD_BASE(2, 2, 3, 0x00a0, 0x10, 11, 1), + PIN_FIELD_BASE(3, 3, 3, 0x00a0, 0x10, 12, 1), + PIN_FIELD_BASE(4, 4, 3, 0x00a0, 0x10, 13, 1), + PIN_FIELD_BASE(5, 5, 3, 0x00a0, 0x10, 14, 1), + PIN_FIELD_BASE(6, 6, 4, 0x0080, 0x10, 13, 1), + PIN_FIELD_BASE(7, 7, 4, 0x0080, 0x10, 14, 1), + PIN_FIELD_BASE(8, 8, 4, 0x0080, 0x10, 15, 1), + PIN_FIELD_BASE(9, 9, 4, 0x0080, 0x10, 16, 1), + PIN_FIELD_BASE(10, 10, 4, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(11, 11, 4, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(12, 12, 4, 0x0080, 0x10, 12, 1), + PIN_FIELD_BASE(13, 13, 6, 0x00a0, 0x10, 4, 1), + PIN_FIELD_BASE(14, 14, 6, 0x00a0, 0x10, 5, 1), + PIN_FIELD_BASE(15, 15, 6, 0x00a0, 0x10, 6, 1), + PIN_FIELD_BASE(16, 16, 6, 0x00a0, 0x10, 7, 1), + PIN_FIELD_BASE(17, 17, 6, 0x00a0, 0x10, 8, 1), + PIN_FIELD_BASE(18, 18, 6, 0x00a0, 0x10, 9, 1), + PIN_FIELD_BASE(19, 19, 3, 0x00a0, 0x10, 0, 1), + PIN_FIELD_BASE(20, 20, 3, 0x00a0, 0x10, 1, 1), + PIN_FIELD_BASE(21, 21, 3, 0x00a0, 0x10, 2, 1), + PIN_FIELD_BASE(22, 22, 3, 0x00a0, 0x10, 3, 1), + PIN_FIELD_BASE(23, 23, 3, 0x00a0, 0x10, 4, 1), + PIN_FIELD_BASE(24, 24, 5, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(25, 25, 3, 0x00a0, 0x10, 5, 1), + PIN_FIELD_BASE(26, 26, 3, 0x00a0, 0x10, 6, 1), + PIN_FIELD_BASE(27, 27, 3, 0x00a0, 0x10, 7, 1), + PIN_FIELD_BASE(28, 28, 3, 0x00a0, 0x10, 8, 1), + PIN_FIELD_BASE(29, 29, 6, 0x00a0, 0x10, 10, 1), + PIN_FIELD_BASE(30, 30, 6, 0x00a0, 0x10, 12, 1), + PIN_FIELD_BASE(31, 31, 6, 0x00a0, 0x10, 13, 1), + PIN_FIELD_BASE(32, 32, 6, 0x00a0, 0x10, 11, 1), + PIN_FIELD_BASE(36, 36, 8, 0x00c0, 0x10, 0, 1), + PIN_FIELD_BASE(37, 37, 8, 0x00c0, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 8, 0x00c0, 0x10, 2, 1), + PIN_FIELD_BASE(39, 39, 8, 0x00c0, 0x10, 3, 1), + PIN_FIELD_BASE(40, 40, 8, 0x00c0, 0x10, 4, 1), + PIN_FIELD_BASE(41, 41, 4, 0x0080, 0x10, 20, 1), + PIN_FIELD_BASE(42, 42, 4, 0x0080, 0x10, 17, 1), + PIN_FIELD_BASE(43, 43, 4, 0x0080, 0x10, 19, 1), + PIN_FIELD_BASE(44, 44, 4, 0x0080, 0x10, 21, 1), + PIN_FIELD_BASE(45, 45, 4, 0x0080, 0x10, 18, 1), + PIN_FIELD_BASE(46, 46, 4, 0x0080, 0x10, 22, 1), + PIN_FIELD_BASE(47, 47, 4, 0x0080, 0x10, 23, 1), + PIN_FIELD_BASE(48, 48, 3, 0x00a0, 0x10, 25, 1), + PIN_FIELD_BASE(49, 49, 3, 0x00a0, 0x10, 23, 1), + PIN_FIELD_BASE(50, 50, 3, 0x00a0, 0x10, 26, 1), + PIN_FIELD_BASE(51, 51, 3, 0x00a0, 0x10, 24, 1), + PIN_FIELD_BASE(52, 52, 3, 0x00a0, 0x10, 17, 1), + PIN_FIELD_BASE(53, 53, 3, 0x00a0, 0x10, 18, 1), + PIN_FIELD_BASE(54, 54, 3, 0x00a0, 0x10, 15, 1), + PIN_FIELD_BASE(55, 55, 3, 0x00a0, 0x10, 16, 1), + PIN_FIELD_BASE(56, 56, 5, 0x0070, 0x10, 8, 1), + PIN_FIELD_BASE(57, 57, 5, 0x0070, 0x10, 9, 1), + PIN_FIELD_BASE(58, 58, 3, 0x00a0, 0x10, 22, 1), + PIN_FIELD_BASE(59, 59, 3, 0x00a0, 0x10, 21, 1), + PIN_FIELD_BASE(60, 60, 8, 0x00c0, 0x10, 21, 1), + PIN_FIELD_BASE(61, 61, 8, 0x00c0, 0x10, 22, 1), + PIN_FIELD_BASE(62, 62, 8, 0x00c0, 0x10, 24, 1), + PIN_FIELD_BASE(63, 63, 8, 0x00c0, 0x10, 23, 1), + PIN_FIELD_BASE(64, 64, 8, 0x00c0, 0x10, 25, 1), + PIN_FIELD_BASE(65, 65, 8, 0x00c0, 0x10, 26, 1), + PIN_FIELD_BASE(66, 66, 8, 0x00c0, 0x10, 28, 1), + PIN_FIELD_BASE(67, 67, 8, 0x00c0, 0x10, 27, 1), + PIN_FIELD_BASE(68, 68, 5, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(69, 69, 5, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(70, 70, 5, 0x0070, 0x10, 6, 1), + PIN_FIELD_BASE(71, 71, 5, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(72, 72, 5, 0x0070, 0x10, 10, 1), + PIN_FIELD_BASE(73, 73, 5, 0x0070, 0x10, 11, 1), + PIN_FIELD_BASE(74, 74, 5, 0x0070, 0x10, 13, 1), + PIN_FIELD_BASE(75, 75, 5, 0x0070, 0x10, 12, 1), + PIN_FIELD_BASE(76, 76, 5, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(89, 89, 4, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(90, 90, 4, 0x0080, 0x10, 24, 1), + PIN_FIELD_BASE(91, 91, 4, 0x0080, 0x10, 8, 1), + PIN_FIELD_BASE(92, 92, 8, 0x00c0, 0x10, 5, 1), + PIN_FIELD_BASE(93, 93, 8, 0x00c0, 0x10, 6, 1), + PIN_FIELD_BASE(94, 94, 8, 0x00c0, 0x10, 7, 1), + PIN_FIELD_BASE(95, 95, 8, 0x00c0, 0x10, 8, 1), + PIN_FIELD_BASE(96, 96, 8, 0x00c0, 0x10, 9, 1), + PIN_FIELD_BASE(99, 99, 1, 0x00a0, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 1, 0x00a0, 0x10, 1, 1), + PIN_FIELD_BASE(101, 101, 1, 0x00a0, 0x10, 10, 1), + PIN_FIELD_BASE(102, 102, 1, 0x00a0, 0x10, 11, 1), + PIN_FIELD_BASE(103, 103, 1, 0x00a0, 0x10, 12, 1), + PIN_FIELD_BASE(104, 104, 1, 0x00a0, 0x10, 13, 1), + PIN_FIELD_BASE(105, 105, 1, 0x00a0, 0x10, 14, 1), + PIN_FIELD_BASE(106, 106, 1, 0x00a0, 0x10, 15, 1), + PIN_FIELD_BASE(107, 107, 1, 0x00a0, 0x10, 16, 1), + PIN_FIELD_BASE(108, 108, 1, 0x00a0, 0x10, 17, 1), + PIN_FIELD_BASE(109, 109, 1, 0x00a0, 0x10, 2, 1), + PIN_FIELD_BASE(110, 110, 1, 0x00a0, 0x10, 3, 1), + PIN_FIELD_BASE(111, 111, 1, 0x00a0, 0x10, 4, 1), + PIN_FIELD_BASE(112, 112, 1, 0x00a0, 0x10, 5, 1), + PIN_FIELD_BASE(113, 113, 1, 0x00a0, 0x10, 6, 1), + PIN_FIELD_BASE(114, 114, 1, 0x00a0, 0x10, 7, 1), + PIN_FIELD_BASE(115, 115, 1, 0x00a0, 0x10, 8, 1), + PIN_FIELD_BASE(116, 116, 1, 0x00a0, 0x10, 9, 1), + PIN_FIELD_BASE(125, 125, 8, 0x00c0, 0x10, 20, 1), + PIN_FIELD_BASE(126, 126, 8, 0x00c0, 0x10, 29, 1), + PIN_FIELD_BASE(127, 127, 8, 0x00c0, 0x10, 30, 1), + PIN_FIELD_BASE(128, 128, 8, 0x00c0, 0x10, 31, 1), + PIN_FIELD_BASE(129, 129, 8, 0x00c0, 0x10, 10, 1), + PIN_FIELD_BASE(130, 130, 8, 0x00c0, 0x10, 13, 1), + PIN_FIELD_BASE(131, 131, 6, 0x00a0, 0x10, 14, 1), + PIN_FIELD_BASE(132, 132, 6, 0x00a0, 0x10, 17, 1), + PIN_FIELD_BASE(133, 133, 8, 0x00c0, 0x10, 11, 1), + PIN_FIELD_BASE(134, 134, 8, 0x00c0, 0x10, 14, 1), + PIN_FIELD_BASE(135, 135, 6, 0x00a0, 0x10, 15, 1), + PIN_FIELD_BASE(136, 136, 6, 0x00a0, 0x10, 18, 1), + PIN_FIELD_BASE(137, 137, 6, 0x00a0, 0x10, 16, 1), + PIN_FIELD_BASE(138, 138, 6, 0x00a0, 0x10, 19, 1), + PIN_FIELD_BASE(139, 139, 6, 0x00a0, 0x10, 0, 1), + PIN_FIELD_BASE(140, 140, 6, 0x00a0, 0x10, 2, 1), + PIN_FIELD_BASE(141, 141, 6, 0x00a0, 0x10, 1, 1), + PIN_FIELD_BASE(142, 142, 6, 0x00a0, 0x10, 3, 1), + PIN_FIELD_BASE(143, 143, 8, 0x00c0, 0x10, 12, 1), + PIN_FIELD_BASE(144, 144, 8, 0x00c0, 0x10, 15, 1), + PIN_FIELD_BASE(145, 145, 5, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(146, 146, 5, 0x0070, 0x10, 7, 1), + PIN_FIELD_BASE(147, 147, 3, 0x00a0, 0x10, 19, 1), + PIN_FIELD_BASE(148, 148, 3, 0x00a0, 0x10, 20, 1), + PIN_FIELD_BASE(149, 149, 8, 0x00c0, 0x10, 16, 1), + PIN_FIELD_BASE(150, 150, 8, 0x00c0, 0x10, 17, 1), + PIN_FIELD_BASE(151, 151, 8, 0x00c0, 0x10, 18, 1), + PIN_FIELD_BASE(152, 152, 8, 0x00c0, 0x10, 19, 1), + PIN_FIELD_BASE(156, 156, 9, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(157, 157, 9, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(158, 158, 9, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(159, 159, 9, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(160, 160, 4, 0x0080, 0x10, 26, 1), + PIN_FIELD_BASE(161, 161, 4, 0x0080, 0x10, 25, 1), + PIN_FIELD_BASE(162, 162, 4, 0x0080, 0x10, 30, 1), + PIN_FIELD_BASE(163, 163, 4, 0x0080, 0x10, 29, 1), + PIN_FIELD_BASE(164, 164, 4, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(165, 165, 4, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(166, 166, 4, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(167, 167, 4, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(168, 168, 4, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(169, 169, 4, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(170, 170, 4, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(171, 171, 4, 0x0080, 0x10, 2, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_pupd_range[] = { + PIN_FIELD_BASE(33, 33, 9, 0x0090, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 9, 0x0090, 0x10, 1, 1), + PIN_FIELD_BASE(35, 35, 9, 0x0090, 0x10, 2, 1), + PIN_FIELD_BASE(77, 77, 2, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 2, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(79, 79, 2, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(80, 80, 2, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(81, 81, 2, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(82, 82, 2, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(83, 83, 2, 0x0070, 0x10, 9, 1), + PIN_FIELD_BASE(84, 84, 2, 0x0070, 0x10, 11, 1), + PIN_FIELD_BASE(85, 85, 2, 0x0070, 0x10, 10, 1), + PIN_FIELD_BASE(86, 86, 2, 0x0070, 0x10, 12, 1), + PIN_FIELD_BASE(87, 87, 2, 0x0070, 0x10, 14, 1), + PIN_FIELD_BASE(88, 88, 2, 0x0070, 0x10, 13, 1), + PIN_FIELD_BASE(97, 97, 1, 0x00b0, 0x10, 1, 1), + PIN_FIELD_BASE(98, 98, 1, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(117, 117, 1, 0x00b0, 0x10, 2, 1), + PIN_FIELD_BASE(118, 118, 1, 0x00b0, 0x10, 3, 1), + PIN_FIELD_BASE(119, 119, 1, 0x00b0, 0x10, 4, 1), + PIN_FIELD_BASE(120, 120, 1, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(121, 121, 1, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(122, 122, 1, 0x00b0, 0x10, 7, 1), + PIN_FIELD_BASE(123, 123, 1, 0x00b0, 0x10, 8, 1), + PIN_FIELD_BASE(124, 124, 1, 0x00b0, 0x10, 9, 1), + PIN_FIELD_BASE(153, 153, 2, 0x0070, 0x10, 6, 1), + PIN_FIELD_BASE(154, 154, 2, 0x0070, 0x10, 7, 1), + PIN_FIELD_BASE(155, 155, 2, 0x0070, 0x10, 8, 1), + PIN_FIELD_BASE(172, 172, 9, 0x0090, 0x10, 7, 1), + PIN_FIELD_BASE(173, 173, 9, 0x0090, 0x10, 8, 1), + PIN_FIELD_BASE(174, 174, 9, 0x0090, 0x10, 3, 1), + PIN_FIELD_BASE(175, 175, 9, 0x0090, 0x10, 4, 1), + PIN_FIELD_BASE(176, 176, 9, 0x0090, 0x10, 5, 1), + PIN_FIELD_BASE(177, 177, 9, 0x0090, 0x10, 9, 1), + PIN_FIELD_BASE(178, 178, 9, 0x0090, 0x10, 10, 1), + PIN_FIELD_BASE(179, 179, 9, 0x0090, 0x10, 11, 1), + PIN_FIELD_BASE(180, 180, 9, 0x0090, 0x10, 12, 1), + PIN_FIELD_BASE(181, 181, 9, 0x0090, 0x10, 13, 1), + PIN_FIELD_BASE(182, 182, 9, 0x0090, 0x10, 14, 1), + PIN_FIELD_BASE(183, 183, 9, 0x0090, 0x10, 6, 1), + PIN_FIELD_BASE(184, 184, 7, 0x0070, 0x10, 10, 1), + PIN_FIELD_BASE(185, 185, 7, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(186, 186, 7, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(187, 187, 7, 0x0070, 0x10, 11, 1), + PIN_FIELD_BASE(188, 188, 7, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(189, 189, 7, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(190, 190, 7, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(191, 191, 7, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(192, 192, 7, 0x0070, 0x10, 6, 1), + PIN_FIELD_BASE(193, 193, 7, 0x0070, 0x10, 7, 1), + PIN_FIELD_BASE(194, 194, 7, 0x0070, 0x10, 8, 1), + PIN_FIELD_BASE(195, 195, 7, 0x0070, 0x10, 9, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_r0_range[] = { + PIN_FIELD_BASE(33, 33, 9, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 9, 0x00b0, 0x10, 1, 1), + PIN_FIELD_BASE(35, 35, 9, 0x00b0, 0x10, 2, 1), + PIN_FIELD_BASE(77, 77, 2, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 2, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(79, 79, 2, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(80, 80, 2, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(81, 81, 2, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(82, 82, 2, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(83, 83, 2, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(84, 84, 2, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(85, 85, 2, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(86, 86, 2, 0x0080, 0x10, 12, 1), + PIN_FIELD_BASE(87, 87, 2, 0x0080, 0x10, 14, 1), + PIN_FIELD_BASE(88, 88, 2, 0x0080, 0x10, 13, 1), + PIN_FIELD_BASE(97, 97, 1, 0x00d0, 0x10, 1, 1), + PIN_FIELD_BASE(98, 98, 1, 0x00d0, 0x10, 0, 1), + PIN_FIELD_BASE(117, 117, 1, 0x00d0, 0x10, 2, 1), + PIN_FIELD_BASE(118, 118, 1, 0x00d0, 0x10, 3, 1), + PIN_FIELD_BASE(119, 119, 1, 0x00d0, 0x10, 4, 1), + PIN_FIELD_BASE(120, 120, 1, 0x00d0, 0x10, 5, 1), + PIN_FIELD_BASE(121, 121, 1, 0x00d0, 0x10, 6, 1), + PIN_FIELD_BASE(122, 122, 1, 0x00d0, 0x10, 7, 1), + PIN_FIELD_BASE(123, 123, 1, 0x00d0, 0x10, 8, 1), + PIN_FIELD_BASE(124, 124, 1, 0x00d0, 0x10, 9, 1), + PIN_FIELD_BASE(153, 153, 2, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(154, 154, 2, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(155, 155, 2, 0x0080, 0x10, 8, 1), + PIN_FIELD_BASE(172, 172, 9, 0x00b0, 0x10, 7, 1), + PIN_FIELD_BASE(173, 173, 9, 0x00b0, 0x10, 8, 1), + PIN_FIELD_BASE(174, 174, 9, 0x00b0, 0x10, 3, 1), + PIN_FIELD_BASE(175, 175, 9, 0x00b0, 0x10, 4, 1), + PIN_FIELD_BASE(176, 176, 9, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(177, 177, 9, 0x00b0, 0x10, 9, 1), + PIN_FIELD_BASE(178, 178, 9, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(179, 179, 9, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(180, 180, 9, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(181, 181, 9, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(182, 182, 9, 0x00b0, 0x10, 14, 1), + PIN_FIELD_BASE(183, 183, 9, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(184, 184, 7, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(185, 185, 7, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(186, 186, 7, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(187, 187, 7, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(188, 188, 7, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(189, 189, 7, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(190, 190, 7, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(191, 191, 7, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(192, 192, 7, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(193, 193, 7, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(194, 194, 7, 0x0080, 0x10, 8, 1), + PIN_FIELD_BASE(195, 195, 7, 0x0080, 0x10, 9, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_r1_range[] = { + PIN_FIELD_BASE(33, 33, 9, 0x00c0, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 9, 0x00c0, 0x10, 1, 1), + PIN_FIELD_BASE(35, 35, 9, 0x00c0, 0x10, 2, 1), + PIN_FIELD_BASE(77, 77, 2, 0x0090, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 2, 0x0090, 0x10, 1, 1), + PIN_FIELD_BASE(79, 79, 2, 0x0090, 0x10, 2, 1), + PIN_FIELD_BASE(80, 80, 2, 0x0090, 0x10, 3, 1), + PIN_FIELD_BASE(81, 81, 2, 0x0090, 0x10, 4, 1), + PIN_FIELD_BASE(82, 82, 2, 0x0090, 0x10, 5, 1), + PIN_FIELD_BASE(83, 83, 2, 0x0090, 0x10, 9, 1), + PIN_FIELD_BASE(84, 84, 2, 0x0090, 0x10, 11, 1), + PIN_FIELD_BASE(85, 85, 2, 0x0090, 0x10, 10, 1), + PIN_FIELD_BASE(86, 86, 2, 0x0090, 0x10, 12, 1), + PIN_FIELD_BASE(87, 87, 2, 0x0090, 0x10, 14, 1), + PIN_FIELD_BASE(88, 88, 2, 0x0090, 0x10, 13, 1), + PIN_FIELD_BASE(97, 97, 1, 0x00e0, 0x10, 1, 1), + PIN_FIELD_BASE(98, 98, 1, 0x00e0, 0x10, 0, 1), + PIN_FIELD_BASE(117, 117, 1, 0x00e0, 0x10, 2, 1), + PIN_FIELD_BASE(118, 118, 1, 0x00e0, 0x10, 3, 1), + PIN_FIELD_BASE(119, 119, 1, 0x00e0, 0x10, 4, 1), + PIN_FIELD_BASE(120, 120, 1, 0x00e0, 0x10, 5, 1), + PIN_FIELD_BASE(121, 121, 1, 0x00e0, 0x10, 6, 1), + PIN_FIELD_BASE(122, 122, 1, 0x00e0, 0x10, 7, 1), + PIN_FIELD_BASE(123, 123, 1, 0x00e0, 0x10, 8, 1), + PIN_FIELD_BASE(124, 124, 1, 0x00e0, 0x10, 9, 1), + PIN_FIELD_BASE(153, 153, 2, 0x0090, 0x10, 6, 1), + PIN_FIELD_BASE(154, 154, 2, 0x0090, 0x10, 7, 1), + PIN_FIELD_BASE(155, 155, 2, 0x0090, 0x10, 8, 1), + PIN_FIELD_BASE(172, 172, 9, 0x00c0, 0x10, 7, 1), + PIN_FIELD_BASE(173, 173, 9, 0x00c0, 0x10, 8, 1), + PIN_FIELD_BASE(174, 174, 9, 0x00c0, 0x10, 3, 1), + PIN_FIELD_BASE(175, 175, 9, 0x00c0, 0x10, 4, 1), + PIN_FIELD_BASE(176, 176, 9, 0x00c0, 0x10, 5, 1), + PIN_FIELD_BASE(177, 177, 9, 0x00c0, 0x10, 9, 1), + PIN_FIELD_BASE(178, 178, 9, 0x00c0, 0x10, 10, 1), + PIN_FIELD_BASE(179, 179, 9, 0x00c0, 0x10, 11, 1), + PIN_FIELD_BASE(180, 180, 9, 0x00c0, 0x10, 12, 1), + PIN_FIELD_BASE(181, 181, 9, 0x00c0, 0x10, 13, 1), + PIN_FIELD_BASE(182, 182, 9, 0x00c0, 0x10, 14, 1), + PIN_FIELD_BASE(183, 183, 9, 0x00c0, 0x10, 6, 1), + PIN_FIELD_BASE(184, 184, 7, 0x0090, 0x10, 10, 1), + PIN_FIELD_BASE(185, 185, 7, 0x0090, 0x10, 0, 1), + PIN_FIELD_BASE(186, 186, 7, 0x0090, 0x10, 1, 1), + PIN_FIELD_BASE(187, 187, 7, 0x0090, 0x10, 11, 1), + PIN_FIELD_BASE(188, 188, 7, 0x0090, 0x10, 2, 1), + PIN_FIELD_BASE(189, 189, 7, 0x0090, 0x10, 3, 1), + PIN_FIELD_BASE(190, 190, 7, 0x0090, 0x10, 4, 1), + PIN_FIELD_BASE(191, 191, 7, 0x0090, 0x10, 5, 1), + PIN_FIELD_BASE(192, 192, 7, 0x0090, 0x10, 6, 1), + PIN_FIELD_BASE(193, 193, 7, 0x0090, 0x10, 7, 1), + PIN_FIELD_BASE(194, 194, 7, 0x0090, 0x10, 8, 1), + PIN_FIELD_BASE(195, 195, 7, 0x0090, 0x10, 9, 1), +}; + +static const struct mtk_pin_field_calc mt6878_pin_drv_range[] = { + PIN_FIELD_BASE(0, 0, 3, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(1, 1, 3, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(2, 2, 3, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(3, 3, 3, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(4, 4, 3, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(5, 5, 3, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(6, 6, 4, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(7, 7, 4, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(8, 8, 4, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(9, 9, 4, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(10, 10, 4, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(11, 11, 4, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(12, 12, 4, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(13, 13, 6, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(14, 14, 6, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(15, 15, 6, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(16, 16, 6, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(17, 17, 6, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(18, 18, 6, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(19, 19, 3, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(20, 20, 3, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(21, 21, 3, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(22, 22, 3, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(23, 23, 3, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(24, 24, 5, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(25, 25, 3, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(26, 26, 3, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(27, 27, 3, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(28, 28, 3, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(29, 29, 6, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(30, 30, 6, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(31, 31, 6, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(32, 32, 6, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(33, 33, 9, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(34, 34, 9, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(35, 35, 9, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(36, 36, 8, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(37, 37, 8, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(38, 38, 8, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(39, 39, 8, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(40, 40, 8, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(41, 41, 4, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(42, 42, 4, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(43, 43, 4, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(44, 44, 4, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(45, 45, 4, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(46, 46, 4, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(47, 47, 4, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(48, 48, 3, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(49, 49, 3, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(50, 50, 3, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(51, 51, 3, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(52, 52, 3, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(53, 53, 3, 0x0010, 0x10, 15, 3), + PIN_FIELD_BASE(54, 54, 3, 0x0010, 0x10, 24, 3), + PIN_FIELD_BASE(55, 55, 3, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(56, 56, 5, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(57, 57, 5, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(58, 58, 3, 0x0020, 0x10, 6, 3), + PIN_FIELD_BASE(59, 59, 3, 0x0020, 0x10, 3, 3), + PIN_FIELD_BASE(60, 60, 8, 0x0020, 0x10, 0, 3), + PIN_FIELD_BASE(61, 61, 8, 0x0020, 0x10, 3, 3), + PIN_FIELD_BASE(62, 62, 8, 0x0020, 0x10, 9, 3), + PIN_FIELD_BASE(63, 63, 8, 0x0020, 0x10, 6, 3), + PIN_FIELD_BASE(64, 64, 8, 0x0020, 0x10, 12, 3), + PIN_FIELD_BASE(65, 65, 8, 0x0020, 0x10, 15, 3), + PIN_FIELD_BASE(66, 66, 8, 0x0020, 0x10, 21, 3), + PIN_FIELD_BASE(67, 67, 8, 0x0020, 0x10, 18, 3), + PIN_FIELD_BASE(68, 68, 5, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(69, 69, 5, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(70, 70, 5, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(71, 71, 5, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(72, 72, 5, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(73, 73, 5, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(74, 74, 5, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(75, 75, 5, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(76, 76, 5, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(77, 77, 2, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(78, 78, 2, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(79, 79, 2, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(80, 80, 2, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(81, 81, 2, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(82, 82, 2, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(83, 83, 2, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(84, 84, 2, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(85, 85, 2, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(86, 86, 2, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(87, 87, 2, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(88, 88, 2, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(89, 89, 4, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(90, 90, 4, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(91, 91, 4, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(92, 92, 8, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(93, 93, 8, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(94, 94, 8, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(95, 95, 8, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(96, 96, 8, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(97, 97, 1, 0x0020, 0x10, 18, 3), + PIN_FIELD_BASE(98, 98, 1, 0x0020, 0x10, 15, 3), + PIN_FIELD_BASE(99, 99, 1, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(100, 100, 1, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(101, 101, 1, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(102, 102, 1, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(103, 103, 1, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(104, 104, 1, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(105, 105, 1, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(106, 106, 1, 0x0010, 0x10, 15, 3), + PIN_FIELD_BASE(107, 107, 1, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(108, 108, 1, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(109, 109, 1, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(110, 110, 1, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(111, 111, 1, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(112, 112, 1, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(113, 113, 1, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(114, 114, 1, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(115, 115, 1, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(116, 116, 1, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(117, 117, 1, 0x0010, 0x10, 24, 3), + PIN_FIELD_BASE(118, 118, 1, 0x0010, 0x10, 27, 3), + PIN_FIELD_BASE(119, 119, 1, 0x0020, 0x10, 0, 3), + PIN_FIELD_BASE(120, 120, 1, 0x0020, 0x10, 3, 3), + PIN_FIELD_BASE(121, 121, 1, 0x0020, 0x10, 6, 3), + PIN_FIELD_BASE(122, 122, 1, 0x0020, 0x10, 9, 3), + PIN_FIELD_BASE(123, 123, 1, 0x0020, 0x10, 12, 3), + PIN_FIELD_BASE(124, 124, 1, 0x0020, 0x10, 12, 3), + PIN_FIELD_BASE(125, 125, 8, 0x0010, 0x10, 27, 3), + PIN_FIELD_BASE(126, 126, 8, 0x0020, 0x10, 24, 3), + PIN_FIELD_BASE(127, 127, 8, 0x0020, 0x10, 27, 3), + PIN_FIELD_BASE(128, 128, 8, 0x0030, 0x10, 0, 3), + PIN_FIELD_BASE(129, 129, 8, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(130, 130, 8, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(131, 131, 6, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(132, 132, 6, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(133, 133, 8, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(134, 134, 8, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(135, 135, 6, 0x0010, 0x10, 15, 3), + PIN_FIELD_BASE(136, 136, 6, 0x0010, 0x10, 24, 3), + PIN_FIELD_BASE(137, 137, 6, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(138, 138, 6, 0x0010, 0x10, 27, 3), + PIN_FIELD_BASE(139, 139, 6, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(140, 140, 6, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(141, 141, 6, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(142, 142, 6, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(143, 143, 8, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(144, 144, 8, 0x0010, 0x10, 15, 3), + PIN_FIELD_BASE(145, 145, 5, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(146, 146, 5, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(147, 147, 3, 0x0010, 0x10, 27, 3), + PIN_FIELD_BASE(148, 148, 3, 0x0020, 0x10, 0, 3), + PIN_FIELD_BASE(149, 149, 8, 0x0010, 0x10, 18, 3), + PIN_FIELD_BASE(150, 150, 8, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(151, 151, 8, 0x0010, 0x10, 24, 3), + PIN_FIELD_BASE(152, 152, 8, 0x0010, 0x10, 24, 3), + PIN_FIELD_BASE(153, 153, 2, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(154, 154, 2, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(155, 155, 2, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(156, 156, 9, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(157, 157, 9, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(158, 158, 9, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(159, 159, 9, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(160, 160, 4, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(161, 161, 4, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(162, 162, 4, 0x0010, 0x10, 21, 3), + PIN_FIELD_BASE(163, 163, 4, 0x0010, 0x10, 24, 3), + PIN_FIELD_BASE(164, 164, 4, 0x0010, 0x10, 15, 3), + PIN_FIELD_BASE(165, 165, 4, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(166, 166, 4, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(167, 167, 4, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(168, 168, 4, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(169, 169, 4, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(170, 170, 4, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(171, 171, 4, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(172, 172, 9, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(173, 173, 9, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(174, 174, 9, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(175, 175, 9, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(176, 176, 9, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(177, 177, 9, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(178, 178, 9, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(179, 179, 9, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(180, 180, 9, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(181, 181, 9, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(182, 182, 9, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(183, 183, 9, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(184, 184, 7, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(185, 185, 7, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(186, 186, 7, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(187, 187, 7, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(188, 188, 7, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(189, 189, 7, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(190, 190, 7, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(191, 191, 7, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(192, 192, 7, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(193, 193, 7, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(194, 194, 7, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(195, 195, 7, 0x0000, 0x10, 27, 3), +}; + +static const struct mtk_pin_field_calc mt6878_pin_drv_adv_range[] = { + PIN_FIELD_BASE(19, 19, 3, 0x0030, 0x10, 0, 3), + PIN_FIELD_BASE(24, 24, 5, 0x0020, 0x10, 0, 3), + PIN_FIELD_BASE(25, 25, 3, 0x0030, 0x10, 3, 3), + PIN_FIELD_BASE(26, 26, 3, 0x0030, 0x10, 6, 3), + PIN_FIELD_BASE(52, 52, 3, 0x0030, 0x10, 12, 3), + PIN_FIELD_BASE(53, 53, 3, 0x0030, 0x10, 15, 3), + PIN_FIELD_BASE(55, 55, 3, 0x0030, 0x10, 9, 3), + PIN_FIELD_BASE(60, 60, 8, 0x0050, 0x10, 12, 3), + PIN_FIELD_BASE(61, 61, 8, 0x0050, 0x10, 15, 3), + PIN_FIELD_BASE(62, 62, 8, 0x0050, 0x10, 21, 3), + PIN_FIELD_BASE(63, 63, 8, 0x0050, 0x10, 18, 3), + PIN_FIELD_BASE(64, 64, 8, 0x0050, 0x10, 24, 3), + PIN_FIELD_BASE(65, 65, 8, 0x0050, 0x10, 27, 3), + PIN_FIELD_BASE(66, 66, 8, 0x0060, 0x10, 3, 3), + PIN_FIELD_BASE(67, 67, 8, 0x0060, 0x10, 0, 3), + PIN_FIELD_BASE(92, 92, 8, 0x0040, 0x10, 0, 3), + PIN_FIELD_BASE(93, 93, 8, 0x0040, 0x10, 3, 3), + PIN_FIELD_BASE(94, 94, 8, 0x0040, 0x10, 6, 3), + PIN_FIELD_BASE(95, 95, 8, 0x0040, 0x10, 9, 3), + PIN_FIELD_BASE(96, 96, 8, 0x0040, 0x10, 12, 3), + PIN_FIELD_BASE(125, 125, 8, 0x0050, 0x10, 9, 3), + PIN_FIELD_BASE(126, 126, 8, 0x0060, 0x10, 6, 3), + PIN_FIELD_BASE(127, 127, 8, 0x0060, 0x10, 9, 3), + PIN_FIELD_BASE(128, 128, 8, 0x0060, 0x10, 12, 3), + PIN_FIELD_BASE(129, 129, 8, 0x0040, 0x10, 15, 3), + PIN_FIELD_BASE(130, 130, 8, 0x0040, 0x10, 24, 3), + PIN_FIELD_BASE(131, 131, 6, 0x0030, 0x10, 12, 3), + PIN_FIELD_BASE(132, 132, 6, 0x0030, 0x10, 21, 3), + PIN_FIELD_BASE(133, 133, 8, 0x0040, 0x10, 18, 3), + PIN_FIELD_BASE(134, 134, 8, 0x0040, 0x10, 27, 3), + PIN_FIELD_BASE(135, 135, 6, 0x0030, 0x10, 15, 3), + PIN_FIELD_BASE(136, 136, 6, 0x0030, 0x10, 24, 3), + PIN_FIELD_BASE(137, 137, 6, 0x0030, 0x10, 18, 3), + PIN_FIELD_BASE(138, 138, 6, 0x0030, 0x10, 27, 3), + PIN_FIELD_BASE(139, 139, 6, 0x0030, 0x10, 0, 3), + PIN_FIELD_BASE(140, 140, 6, 0x0030, 0x10, 6, 3), + PIN_FIELD_BASE(141, 141, 6, 0x0030, 0x10, 3, 3), + PIN_FIELD_BASE(142, 142, 6, 0x0030, 0x10, 9, 3), + PIN_FIELD_BASE(143, 143, 8, 0x0040, 0x10, 21, 3), + PIN_FIELD_BASE(144, 144, 8, 0x0050, 0x10, 0, 3), + PIN_FIELD_BASE(145, 145, 5, 0x0020, 0x10, 3, 3), + PIN_FIELD_BASE(146, 146, 5, 0x0020, 0x10, 6, 3), + PIN_FIELD_BASE(147, 147, 3, 0x0030, 0x10, 18, 3), + PIN_FIELD_BASE(148, 148, 3, 0x0030, 0x10, 21, 3), + PIN_FIELD_BASE(149, 149, 8, 0x0050, 0x10, 3, 3), + PIN_FIELD_BASE(150, 150, 8, 0x0050, 0x10, 6, 3), + PIN_FIELD_BASE(156, 156, 9, 0x0020, 0x10, 0, 5), + PIN_FIELD_BASE(157, 157, 9, 0x0020, 0x10, 5, 5), + PIN_FIELD_BASE(158, 158, 9, 0x0020, 0x10, 10, 5), + PIN_FIELD_BASE(159, 159, 9, 0x0020, 0x10, 15, 5), +}; + +static const struct mtk_pin_field_calc mt6878_pin_rsel_range[] = { + PIN_FIELD_BASE(19, 19, 3, 0x00d0, 0x10, 0, 3), + PIN_FIELD_BASE(24, 24, 5, 0x00a0, 0x10, 0, 3), + PIN_FIELD_BASE(25, 25, 3, 0x00d0, 0x10, 3, 3), + PIN_FIELD_BASE(26, 26, 3, 0x00d0, 0x10, 6, 3), + PIN_FIELD_BASE(52, 52, 3, 0x00d0, 0x10, 12, 3), + PIN_FIELD_BASE(53, 53, 3, 0x00d0, 0x10, 15, 3), + PIN_FIELD_BASE(55, 55, 3, 0x00d0, 0x10, 9, 3), + PIN_FIELD_BASE(60, 60, 8, 0x0110, 0x10, 12, 3), + PIN_FIELD_BASE(61, 61, 8, 0x0110, 0x10, 15, 3), + PIN_FIELD_BASE(62, 62, 8, 0x0110, 0x10, 21, 3), + PIN_FIELD_BASE(63, 63, 8, 0x0110, 0x10, 18, 3), + PIN_FIELD_BASE(64, 64, 8, 0x0110, 0x10, 24, 3), + PIN_FIELD_BASE(65, 65, 8, 0x0110, 0x10, 27, 3), + PIN_FIELD_BASE(66, 66, 8, 0x0120, 0x10, 3, 3), + PIN_FIELD_BASE(67, 67, 8, 0x0120, 0x10, 0, 3), + PIN_FIELD_BASE(92, 92, 8, 0x0100, 0x10, 0, 3), + PIN_FIELD_BASE(93, 93, 8, 0x0100, 0x10, 3, 3), + PIN_FIELD_BASE(94, 94, 8, 0x0100, 0x10, 6, 3), + PIN_FIELD_BASE(95, 95, 8, 0x0100, 0x10, 9, 3), + PIN_FIELD_BASE(96, 96, 8, 0x0100, 0x10, 12, 3), + PIN_FIELD_BASE(125, 125, 8, 0x0110, 0x10, 9, 3), + PIN_FIELD_BASE(126, 126, 8, 0x0120, 0x10, 6, 3), + PIN_FIELD_BASE(127, 127, 8, 0x0120, 0x10, 9, 3), + PIN_FIELD_BASE(128, 128, 8, 0x0120, 0x10, 12, 3), + PIN_FIELD_BASE(129, 129, 8, 0x0100, 0x10, 15, 3), + PIN_FIELD_BASE(130, 130, 8, 0x0100, 0x10, 24, 3), + PIN_FIELD_BASE(131, 131, 6, 0x00d0, 0x10, 12, 3), + PIN_FIELD_BASE(132, 132, 6, 0x00d0, 0x10, 21, 3), + PIN_FIELD_BASE(133, 133, 8, 0x0100, 0x10, 18, 3), + PIN_FIELD_BASE(134, 134, 8, 0x0100, 0x10, 27, 3), + PIN_FIELD_BASE(135, 135, 6, 0x00d0, 0x10, 15, 3), + PIN_FIELD_BASE(136, 136, 6, 0x00d0, 0x10, 24, 3), + PIN_FIELD_BASE(137, 137, 6, 0x00d0, 0x10, 18, 3), + PIN_FIELD_BASE(138, 138, 6, 0x00d0, 0x10, 27, 3), + PIN_FIELD_BASE(139, 139, 6, 0x00d0, 0x10, 0, 3), + PIN_FIELD_BASE(140, 140, 6, 0x00d0, 0x10, 6, 3), + PIN_FIELD_BASE(141, 141, 6, 0x00d0, 0x10, 3, 3), + PIN_FIELD_BASE(142, 142, 6, 0x00d0, 0x10, 9, 3), + PIN_FIELD_BASE(143, 143, 8, 0x0100, 0x10, 21, 3), + PIN_FIELD_BASE(144, 144, 8, 0x0110, 0x10, 0, 3), + PIN_FIELD_BASE(145, 145, 5, 0x00a0, 0x10, 3, 3), + PIN_FIELD_BASE(146, 146, 5, 0x00a0, 0x10, 6, 3), + PIN_FIELD_BASE(147, 147, 3, 0x00d0, 0x10, 18, 3), + PIN_FIELD_BASE(148, 148, 3, 0x00d0, 0x10, 21, 3), + PIN_FIELD_BASE(149, 149, 8, 0x0110, 0x10, 3, 3), + PIN_FIELD_BASE(150, 150, 8, 0x0110, 0x10, 6, 3), +}; + +static const unsigned int mt6878_pull_type[] = { + MTK_PULL_PU_PD_TYPE /* 0 */, + MTK_PULL_PU_PD_TYPE /* 1 */, + MTK_PULL_PU_PD_TYPE /* 2 */, + MTK_PULL_PU_PD_TYPE /* 3 */, + MTK_PULL_PU_PD_TYPE /* 4 */, + MTK_PULL_PU_PD_TYPE /* 5 */, + MTK_PULL_PU_PD_TYPE /* 6 */, + MTK_PULL_PU_PD_TYPE /* 7 */, + MTK_PULL_PU_PD_TYPE /* 8 */, + MTK_PULL_PU_PD_TYPE /* 9 */, + MTK_PULL_PU_PD_TYPE /* 10 */, + MTK_PULL_PU_PD_TYPE /* 11 */, + MTK_PULL_PU_PD_TYPE /* 12 */, + MTK_PULL_PU_PD_TYPE /* 13 */, + MTK_PULL_PU_PD_TYPE /* 14 */, + MTK_PULL_PU_PD_TYPE /* 15 */, + MTK_PULL_PU_PD_TYPE /* 16 */, + MTK_PULL_PU_PD_TYPE /* 17 */, + MTK_PULL_PU_PD_TYPE /* 18 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 19 */, + MTK_PULL_PU_PD_TYPE /* 20 */, + MTK_PULL_PU_PD_TYPE /* 21 */, + MTK_PULL_PU_PD_TYPE /* 22 */, + MTK_PULL_PU_PD_TYPE /* 23 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 24 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 25 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 26 */, + MTK_PULL_PU_PD_TYPE /* 27 */, + MTK_PULL_PU_PD_TYPE /* 28 */, + MTK_PULL_PU_PD_TYPE /* 29 */, + MTK_PULL_PU_PD_TYPE /* 30 */, + MTK_PULL_PU_PD_TYPE /* 31 */, + MTK_PULL_PU_PD_TYPE /* 32 */, + MTK_PULL_PUPD_R1R0_TYPE /* 33 */, + MTK_PULL_PUPD_R1R0_TYPE /* 34 */, + MTK_PULL_PUPD_R1R0_TYPE /* 35 */, + MTK_PULL_PU_PD_TYPE /* 36 */, + MTK_PULL_PU_PD_TYPE /* 37 */, + MTK_PULL_PU_PD_TYPE /* 38 */, + MTK_PULL_PU_PD_TYPE /* 39 */, + MTK_PULL_PU_PD_TYPE /* 40 */, + MTK_PULL_PU_PD_TYPE /* 41 */, + MTK_PULL_PU_PD_TYPE /* 42 */, + MTK_PULL_PU_PD_TYPE /* 43 */, + MTK_PULL_PU_PD_TYPE /* 44 */, + MTK_PULL_PU_PD_TYPE /* 45 */, + MTK_PULL_PU_PD_TYPE /* 46 */, + MTK_PULL_PU_PD_TYPE /* 47 */, + MTK_PULL_PU_PD_TYPE /* 48 */, + MTK_PULL_PU_PD_TYPE /* 49 */, + MTK_PULL_PU_PD_TYPE /* 50 */, + MTK_PULL_PU_PD_TYPE /* 51 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 52 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 53 */, + MTK_PULL_PU_PD_TYPE /* 54 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 55 */, + MTK_PULL_PU_PD_TYPE /* 56 */, + MTK_PULL_PU_PD_TYPE /* 57 */, + MTK_PULL_PU_PD_TYPE /* 58 */, + MTK_PULL_PU_PD_TYPE /* 59 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 60 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 61 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 62 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 63 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 64 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 65 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 66 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 67 */, + MTK_PULL_PU_PD_TYPE /* 68 */, + MTK_PULL_PU_PD_TYPE /* 69 */, + MTK_PULL_PU_PD_TYPE /* 70 */, + MTK_PULL_PU_PD_TYPE /* 71 */, + MTK_PULL_PU_PD_TYPE /* 72 */, + MTK_PULL_PU_PD_TYPE /* 73 */, + MTK_PULL_PU_PD_TYPE /* 74 */, + MTK_PULL_PU_PD_TYPE /* 75 */, + MTK_PULL_PU_PD_TYPE /* 76 */, + MTK_PULL_PUPD_R1R0_TYPE /* 77 */, + MTK_PULL_PUPD_R1R0_TYPE /* 78 */, + MTK_PULL_PUPD_R1R0_TYPE /* 79 */, + MTK_PULL_PUPD_R1R0_TYPE /* 80 */, + MTK_PULL_PUPD_R1R0_TYPE /* 81 */, + MTK_PULL_PUPD_R1R0_TYPE /* 82 */, + MTK_PULL_PUPD_R1R0_TYPE /* 83 */, + MTK_PULL_PUPD_R1R0_TYPE /* 84 */, + MTK_PULL_PUPD_R1R0_TYPE /* 85 */, + MTK_PULL_PUPD_R1R0_TYPE /* 86 */, + MTK_PULL_PUPD_R1R0_TYPE /* 87 */, + MTK_PULL_PUPD_R1R0_TYPE /* 88 */, + MTK_PULL_PU_PD_TYPE /* 89 */, + MTK_PULL_PU_PD_TYPE /* 90 */, + MTK_PULL_PU_PD_TYPE /* 91 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 92 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 93 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 94 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 95 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 96 */, + MTK_PULL_PUPD_R1R0_TYPE /* 97 */, + MTK_PULL_PUPD_R1R0_TYPE /* 98 */, + MTK_PULL_PU_PD_TYPE /* 99 */, + MTK_PULL_PU_PD_TYPE /* 100 */, + MTK_PULL_PU_PD_TYPE /* 101 */, + MTK_PULL_PU_PD_TYPE /* 102 */, + MTK_PULL_PU_PD_TYPE /* 103 */, + MTK_PULL_PU_PD_TYPE /* 104 */, + MTK_PULL_PU_PD_TYPE /* 105 */, + MTK_PULL_PU_PD_TYPE /* 106 */, + MTK_PULL_PU_PD_TYPE /* 107 */, + MTK_PULL_PU_PD_TYPE /* 108 */, + MTK_PULL_PU_PD_TYPE /* 109 */, + MTK_PULL_PU_PD_TYPE /* 110 */, + MTK_PULL_PU_PD_TYPE /* 111 */, + MTK_PULL_PU_PD_TYPE /* 112 */, + MTK_PULL_PU_PD_TYPE /* 113 */, + MTK_PULL_PU_PD_TYPE /* 114 */, + MTK_PULL_PU_PD_TYPE /* 115 */, + MTK_PULL_PU_PD_TYPE /* 116 */, + MTK_PULL_PUPD_R1R0_TYPE /* 117 */, + MTK_PULL_PUPD_R1R0_TYPE /* 118 */, + MTK_PULL_PUPD_R1R0_TYPE /* 119 */, + MTK_PULL_PUPD_R1R0_TYPE /* 120 */, + MTK_PULL_PUPD_R1R0_TYPE /* 121 */, + MTK_PULL_PUPD_R1R0_TYPE /* 122 */, + MTK_PULL_PUPD_R1R0_TYPE /* 123 */, + MTK_PULL_PUPD_R1R0_TYPE /* 124 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 125 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 126 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 127 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 128 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 129 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 130 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 131 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 132 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 133 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 134 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 135 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 136 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 137 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 138 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 139 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 140 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 141 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 142 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 143 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 144 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 145 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 146 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 147 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 148 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 149 */, + MTK_PULL_PU_PD_RSEL_TYPE /* 150 */, + MTK_PULL_PU_PD_TYPE /* 151 */, + MTK_PULL_PU_PD_TYPE /* 152 */, + MTK_PULL_PUPD_R1R0_TYPE /* 153 */, + MTK_PULL_PUPD_R1R0_TYPE /* 154 */, + MTK_PULL_PUPD_R1R0_TYPE /* 155 */, + MTK_PULL_PU_PD_TYPE /* 156 */, + MTK_PULL_PU_PD_TYPE /* 157 */, + MTK_PULL_PU_PD_TYPE /* 158 */, + MTK_PULL_PU_PD_TYPE /* 159 */, + MTK_PULL_PU_PD_TYPE /* 160 */, + MTK_PULL_PU_PD_TYPE /* 161 */, + MTK_PULL_PU_PD_TYPE /* 162 */, + MTK_PULL_PU_PD_TYPE /* 163 */, + MTK_PULL_PU_PD_TYPE /* 164 */, + MTK_PULL_PU_PD_TYPE /* 165 */, + MTK_PULL_PU_PD_TYPE /* 166 */, + MTK_PULL_PU_PD_TYPE /* 167 */, + MTK_PULL_PU_PD_TYPE /* 168 */, + MTK_PULL_PU_PD_TYPE /* 169 */, + MTK_PULL_PU_PD_TYPE /* 170 */, + MTK_PULL_PU_PD_TYPE /* 171 */, + MTK_PULL_PUPD_R1R0_TYPE /* 172 */, + MTK_PULL_PUPD_R1R0_TYPE /* 173 */, + MTK_PULL_PUPD_R1R0_TYPE /* 174 */, + MTK_PULL_PUPD_R1R0_TYPE /* 175 */, + MTK_PULL_PUPD_R1R0_TYPE /* 176 */, + MTK_PULL_PUPD_R1R0_TYPE /* 177 */, + MTK_PULL_PUPD_R1R0_TYPE /* 178 */, + MTK_PULL_PUPD_R1R0_TYPE /* 179 */, + MTK_PULL_PUPD_R1R0_TYPE /* 180 */, + MTK_PULL_PUPD_R1R0_TYPE /* 181 */, + MTK_PULL_PUPD_R1R0_TYPE /* 182 */, + MTK_PULL_PUPD_R1R0_TYPE /* 183 */, + MTK_PULL_PUPD_R1R0_TYPE /* 184 */, + MTK_PULL_PUPD_R1R0_TYPE /* 185 */, + MTK_PULL_PUPD_R1R0_TYPE /* 186 */, + MTK_PULL_PUPD_R1R0_TYPE /* 187 */, + MTK_PULL_PUPD_R1R0_TYPE /* 188 */, + MTK_PULL_PUPD_R1R0_TYPE /* 189 */, + MTK_PULL_PUPD_R1R0_TYPE /* 190 */, + MTK_PULL_PUPD_R1R0_TYPE /* 191 */, + MTK_PULL_PUPD_R1R0_TYPE /* 192 */, + MTK_PULL_PUPD_R1R0_TYPE /* 193 */, + MTK_PULL_PUPD_R1R0_TYPE /* 194 */, + MTK_PULL_PUPD_R1R0_TYPE /* 195 */, +}; + +static const char * const mt6878_pinctrl_register_base_names[] = { + "gpio", "iocfg_bl", "iocfg_bm", "iocfg_br", + "iocfg_bl1", "iocfg_br1", "iocfg_lm", "iocfg_lt", + "iocfg_rm", "iocfg_rt", +}; + +static const struct mtk_eint_hw mt6878_eint_hw = { + .port_mask = 31, + .ports = 1, + .ap_num = 216, + .db_cnt = 36, + .db_time = debounce_time_mt6878, +}; + +static const struct mtk_pin_reg_calc mt6878_reg_cals[PINCTRL_PIN_REG_MAX] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt6878_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt6878_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt6878_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt6878_pin_do_range), + [PINCTRL_PIN_REG_SR] = MTK_RANGE(mt6878_pin_dir_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt6878_pin_smt_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt6878_pin_ies_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt6878_pin_pu_range), + [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt6878_pin_pd_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt6878_pin_drv_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt6878_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt6878_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt6878_pin_r1_range), + [PINCTRL_PIN_REG_DRV_ADV] = MTK_RANGE(mt6878_pin_drv_adv_range), + [PINCTRL_PIN_REG_RSEL] = MTK_RANGE(mt6878_pin_rsel_range), +}; + +static const struct mtk_pin_soc mt6878_data = { + .reg_cal = mt6878_reg_cals, + .pins = mtk_pins_mt6878, + .npins = ARRAY_SIZE(mtk_pins_mt6878), + .ngrps = ARRAY_SIZE(mtk_pins_mt6878), + .eint_pin = eint_pins_mt6878, + .eint_hw = &mt6878_eint_hw, + .nfuncs = 8, + .gpio_m = 0, + .base_names = mt6878_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt6878_pinctrl_register_base_names), + .bias_set_combo = mtk_pinconf_bias_set_combo, + .bias_get_combo = mtk_pinconf_bias_get_combo, + .pull_type = mt6878_pull_type, + .adv_drive_get = mtk_pinconf_adv_drive_get, + .adv_drive_set = mtk_pinconf_adv_drive_set, +}; + +static const struct of_device_id mt6878_pinctrl_of_match[] = { + { .compatible = "mediatek,mt6878-pinctrl", .data = &mt6878_data }, + { } +}; + +static struct platform_driver mt6878_pinctrl_driver = { + .driver = { + .name = "mt6878-pinctrl", + .of_match_table = mt6878_pinctrl_of_match, + .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops), + }, + .probe = mtk_paris_pinctrl_probe, +}; + +static int __init mt6878_pinctrl_init(void) +{ + return platform_driver_register(&mt6878_pinctrl_driver); +} +arch_initcall(mt6878_pinctrl_init); + +MODULE_DESCRIPTION("MediaTek MT6878 Pinctrl Driver"); diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt6878.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6878.h new file mode 100644 index 000000000000..a251af00eff1 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6878.h @@ -0,0 +1,2248 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 MediaTek Inc. + * Author: Light Hsieh <light.hsieh@mediatek.com> + * + * Copyright (C) 2025 Igor Belwon <igor.belwon@mentallysanemainliners.org> + */ + +#ifndef __PINCTRL_MTK_MT6878_H +#define __PINCTRL_MTK_MT6878_H + +#include "pinctrl-paris.h" + +static const struct mtk_pin_desc mtk_pins_mt6878[] = { + MTK_PIN( + 0, "GPIO0", + MTK_EINT_FUNCTION(0, 0), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO0"), + MTK_FUNCTION(1, "TP_GPIO0_AO"), + MTK_FUNCTION(2, "SRCLKENA1"), + MTK_FUNCTION(7, "DBG_MON_A3") + ), + MTK_PIN( + 1, "GPIO1", + MTK_EINT_FUNCTION(0, 1), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO1"), + MTK_FUNCTION(1, "TP_GPIO1_AO"), + MTK_FUNCTION(2, "SRCLKENA1"), + MTK_FUNCTION(3, "SRCLKENA2"), + MTK_FUNCTION(5, "IDDIG"), + MTK_FUNCTION(7, "DBG_MON_A4") + ), + MTK_PIN( + 2, "GPIO2", + MTK_EINT_FUNCTION(0, 2), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO2"), + MTK_FUNCTION(1, "TP_GPIO2_AO"), + MTK_FUNCTION(2, "SRCLKENAI0"), + MTK_FUNCTION(4, "SCP_DMIC_CLK"), + MTK_FUNCTION(5, "DMIC_CLK"), + MTK_FUNCTION(7, "DBG_MON_A5") + ), + MTK_PIN( + 3, "GPIO3", + MTK_EINT_FUNCTION(0, 3), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO3"), + MTK_FUNCTION(1, "TP_GPIO3_AO"), + MTK_FUNCTION(2, "SRCLKENAI1"), + MTK_FUNCTION(4, "SCP_DMIC_DAT"), + MTK_FUNCTION(5, "DMIC_DAT"), + MTK_FUNCTION(7, "DBG_MON_A6") + ), + MTK_PIN( + 4, "GPIO4", + MTK_EINT_FUNCTION(0, 4), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO4"), + MTK_FUNCTION(1, "SPI7_CLK"), + MTK_FUNCTION(2, "TP_GPIO4_AO"), + MTK_FUNCTION(3, "ANT_SEL0"), + MTK_FUNCTION(5, "DMIC1_CLK"), + MTK_FUNCTION(6, "MD_INT4"), + MTK_FUNCTION(7, "DBG_MON_A7") + ), + MTK_PIN( + 5, "GPIO5", + MTK_EINT_FUNCTION(0, 5), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO5"), + MTK_FUNCTION(1, "SPI7_CSB"), + MTK_FUNCTION(2, "TP_GPIO5_AO"), + MTK_FUNCTION(3, "ANT_SEL1"), + MTK_FUNCTION(5, "DMIC1_DAT"), + MTK_FUNCTION(6, "MD_INT0"), + MTK_FUNCTION(7, "DBG_MON_A8") + ), + MTK_PIN( + 6, "GPIO6", + MTK_EINT_FUNCTION(0, 6), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO6"), + MTK_FUNCTION(1, "SPI7_MO"), + MTK_FUNCTION(2, "TP_GPIO6_AO"), + MTK_FUNCTION(3, "ANT_SEL2"), + MTK_FUNCTION(4, "MD32_0_GPIO0"), + MTK_FUNCTION(6, "MD_INT3"), + MTK_FUNCTION(7, "DBG_MON_B0") + ), + MTK_PIN( + 7, "GPIO7", + MTK_EINT_FUNCTION(0, 7), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO7"), + MTK_FUNCTION(1, "SPI7_MI"), + MTK_FUNCTION(2, "TP_GPIO7_AO"), + MTK_FUNCTION(3, "ANT_SEL3"), + MTK_FUNCTION(4, "MD32_1_GPIO0") + ), + MTK_PIN( + 8, "GPIO8", + MTK_EINT_FUNCTION(0, 8), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO8"), + MTK_FUNCTION(2, "SCP_JTAG0_TRSTN_VLP"), + MTK_FUNCTION(3, "SPM_JTAG_TRSTN_VLP"), + MTK_FUNCTION(4, "SSPM_JTAG_TRSTN_VLP"), + MTK_FUNCTION(5, "HFRP_JTAG0_TRSTN"), + MTK_FUNCTION(6, "IO_JTAG_TRSTN"), + MTK_FUNCTION(7, "CONN_BGF_MCU_TDI") + ), + MTK_PIN( + 9, "GPIO9", + MTK_EINT_FUNCTION(0, 9), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO9"), + MTK_FUNCTION(2, "SCP_JTAG0_TCK_VLP"), + MTK_FUNCTION(3, "SPM_JTAG_TCK_VLP"), + MTK_FUNCTION(4, "SSPM_JTAG_TCK_VLP"), + MTK_FUNCTION(5, "HFRP_JTAG0_TCK"), + MTK_FUNCTION(6, "IO_JTAG_TCK"), + MTK_FUNCTION(7, "CONN_BGF_MCU_TRST_B") + ), + MTK_PIN( + 10, "GPIO10", + MTK_EINT_FUNCTION(0, 10), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO10"), + MTK_FUNCTION(2, "SCP_JTAG0_TMS_VLP"), + MTK_FUNCTION(3, "SPM_JTAG_TMS_VLP"), + MTK_FUNCTION(4, "SSPM_JTAG_TMS_VLP"), + MTK_FUNCTION(5, "HFRP_JTAG0_TMS"), + MTK_FUNCTION(6, "IO_JTAG_TMS"), + MTK_FUNCTION(7, "CONN_BGF_MCU_TCK") + ), + MTK_PIN( + 11, "GPIO11", + MTK_EINT_FUNCTION(0, 11), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO11"), + MTK_FUNCTION(2, "SCP_JTAG0_TDI_VLP"), + MTK_FUNCTION(3, "SPM_JTAG_TDI_VLP"), + MTK_FUNCTION(4, "SSPM_JTAG_TDI_VLP"), + MTK_FUNCTION(5, "HFRP_JTAG0_TDI"), + MTK_FUNCTION(6, "IO_JTAG_TDI"), + MTK_FUNCTION(7, "CONN_BGF_MCU_TDO") + ), + MTK_PIN( + 12, "GPIO12", + MTK_EINT_FUNCTION(0, 12), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO12"), + MTK_FUNCTION(2, "SCP_JTAG0_TDO_VLP"), + MTK_FUNCTION(3, "SPM_JTAG_TDO_VLP"), + MTK_FUNCTION(4, "SSPM_JTAG_TDO_VLP"), + MTK_FUNCTION(5, "HFRP_JTAG0_TDO"), + MTK_FUNCTION(6, "IO_JTAG_TDO"), + MTK_FUNCTION(7, "CONN_BGF_MCU_TMS") + ), + MTK_PIN( + 13, "GPIO13", + MTK_EINT_FUNCTION(0, 13), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO13"), + MTK_FUNCTION(1, "MFG_EB_JTAG_TDI"), + MTK_FUNCTION(2, "CONN_WF_MCU_TDI"), + MTK_FUNCTION(3, "SCP_JTAG0_TDI_VCORE"), + MTK_FUNCTION(5, "SPM_JTAG_TDI_VCORE"), + MTK_FUNCTION(6, "MCUPM_JTAG_TDI") + ), + MTK_PIN( + 14, "GPIO14", + MTK_EINT_FUNCTION(0, 14), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO14"), + MTK_FUNCTION(1, "MFG_EB_JTAG_TRSTN"), + MTK_FUNCTION(2, "CONN_WF_MCU_TRST_B"), + MTK_FUNCTION(3, "SCP_JTAG0_TRSTN_VCORE"), + MTK_FUNCTION(5, "SPM_JTAG_TRSTN_VCORE"), + MTK_FUNCTION(6, "MCUPM_JTAG_TRSTN") + ), + MTK_PIN( + 15, "GPIO15", + MTK_EINT_FUNCTION(0, 15), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO15"), + MTK_FUNCTION(1, "MFG_EB_JTAG_TCK"), + MTK_FUNCTION(2, "CONN_WF_MCU_TCK"), + MTK_FUNCTION(3, "SCP_JTAG0_TCK_VCORE"), + MTK_FUNCTION(5, "SPM_JTAG_TCK_VCORE"), + MTK_FUNCTION(6, "MCUPM_JTAG_TCK") + ), + MTK_PIN( + 16, "GPIO16", + MTK_EINT_FUNCTION(0, 16), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO16"), + MTK_FUNCTION(1, "MFG_EB_JTAG_TDO"), + MTK_FUNCTION(2, "CONN_WF_MCU_TDO"), + MTK_FUNCTION(3, "SCP_JTAG0_TDO_VCORE"), + MTK_FUNCTION(5, "SPM_JTAG_TDO_VCORE"), + MTK_FUNCTION(6, "MCUPM_JTAG_TDO") + ), + MTK_PIN( + 17, "GPIO17", + MTK_EINT_FUNCTION(0, 17), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO17"), + MTK_FUNCTION(1, "MFG_EB_JTAG_TMS"), + MTK_FUNCTION(2, "CONN_WF_MCU_TMS"), + MTK_FUNCTION(3, "SCP_JTAG0_TMS_VCORE"), + MTK_FUNCTION(5, "SPM_JTAG_TMS_VCORE"), + MTK_FUNCTION(6, "MCUPM_JTAG_TMS") + ), + MTK_PIN( + 18, "GPIO18", + MTK_EINT_FUNCTION(0, 18), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO18"), + MTK_FUNCTION(2, "CONN_BT_TXD"), + MTK_FUNCTION(3, "CONN_TCXOENA_REQ"), + MTK_FUNCTION(6, "GPS_L1_ELNA_EN") + ), + MTK_PIN( + 19, "GPIO19", + MTK_EINT_FUNCTION(0, 19), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO19"), + MTK_FUNCTION(1, "PWM_0"), + MTK_FUNCTION(3, "SDA10"), + MTK_FUNCTION(4, "MD32_0_GPIO0"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(7, "DBG_MON_A9") + ), + MTK_PIN( + 20, "GPIO20", + MTK_EINT_FUNCTION(0, 20), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO20"), + MTK_FUNCTION(1, "PWM_1"), + MTK_FUNCTION(2, "SPI4_CLK"), + MTK_FUNCTION(4, "GPS_L1_ELNA_EN"), + MTK_FUNCTION(6, "DAP_SONIC_SWCK"), + MTK_FUNCTION(7, "DBG_MON_A10") + ), + MTK_PIN( + 21, "GPIO21", + MTK_EINT_FUNCTION(0, 21), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO21"), + MTK_FUNCTION(1, "PWM_2"), + MTK_FUNCTION(2, "SPI4_CSB"), + MTK_FUNCTION(4, "GPS_L5_ELNA_EN"), + MTK_FUNCTION(5, "IDDIG"), + MTK_FUNCTION(6, "DAP_SONIC_SWD"), + MTK_FUNCTION(7, "DBG_MON_A11") + ), + MTK_PIN( + 22, "GPIO22", + MTK_EINT_FUNCTION(0, 22), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO22"), + MTK_FUNCTION(1, "PWM_3"), + MTK_FUNCTION(2, "SPI4_MO"), + MTK_FUNCTION(4, "EXT_FRAME_SYNC"), + MTK_FUNCTION(5, "VBUSVALID"), + MTK_FUNCTION(6, "DAP_MD32_SWCK"), + MTK_FUNCTION(7, "DBG_MON_A12") + ), + MTK_PIN( + 23, "GPIO23", + MTK_EINT_FUNCTION(0, 23), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO23"), + MTK_FUNCTION(2, "SPI4_MI"), + MTK_FUNCTION(4, "MD32_1_GPIO0"), + MTK_FUNCTION(5, "USB_DRVVBUS"), + MTK_FUNCTION(6, "DAP_MD32_SWD"), + MTK_FUNCTION(7, "DBG_MON_A13") + ), + MTK_PIN( + 24, "GPIO24", + MTK_EINT_FUNCTION(0, 24), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO24"), + MTK_FUNCTION(1, "GPS_L5_ELNA_EN"), + MTK_FUNCTION(2, "SCL12"), + MTK_FUNCTION(3, "SCL10"), + MTK_FUNCTION(4, "CMVREF0"), + MTK_FUNCTION(5, "CONN_WIFI_TXD"), + MTK_FUNCTION(6, "CMFLASH0"), + MTK_FUNCTION(7, "DBG_MON_A14") + ), + MTK_PIN( + 25, "GPIO25", + MTK_EINT_FUNCTION(0, 25), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO25"), + MTK_FUNCTION(1, "SPI6_CLK"), + MTK_FUNCTION(2, "SCL11"), + MTK_FUNCTION(4, "CMVREF1"), + MTK_FUNCTION(6, "CMFLASH1"), + MTK_FUNCTION(7, "DBG_MON_A15") + ), + MTK_PIN( + 26, "GPIO26", + MTK_EINT_FUNCTION(0, 26), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO26"), + MTK_FUNCTION(1, "SPI6_CSB"), + MTK_FUNCTION(2, "SDA11"), + MTK_FUNCTION(3, "USB_DRVVBUS"), + MTK_FUNCTION(4, "CMVREF2"), + MTK_FUNCTION(6, "CMFLASH2"), + MTK_FUNCTION(7, "DBG_MON_A16") + ), + MTK_PIN( + 27, "GPIO27", + MTK_EINT_FUNCTION(0, 27), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO27"), + MTK_FUNCTION(1, "SPI6_MO"), + MTK_FUNCTION(3, "VBUSVALID"), + MTK_FUNCTION(4, "CMVREF3"), + MTK_FUNCTION(5, "DMIC1_CLK"), + MTK_FUNCTION(6, "CMFLASH3"), + MTK_FUNCTION(7, "DBG_MON_A17") + ), + MTK_PIN( + 28, "GPIO28", + MTK_EINT_FUNCTION(0, 28), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO28"), + MTK_FUNCTION(1, "SPI6_MI"), + MTK_FUNCTION(3, "IDDIG"), + MTK_FUNCTION(5, "DMIC1_DAT"), + MTK_FUNCTION(6, "CMFLASH0"), + MTK_FUNCTION(7, "DBG_MON_A18") + ), + MTK_PIN( + 29, "GPIO29", + MTK_EINT_FUNCTION(0, 29), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO29"), + MTK_FUNCTION(1, "I2SIN2_BCK"), + MTK_FUNCTION(2, "TP_UTXD1_VCORE"), + MTK_FUNCTION(3, "MD_UTXD0"), + MTK_FUNCTION(4, "SSPM_UTXD_AO_VCORE"), + MTK_FUNCTION(5, "MD32_1_TXD"), + MTK_FUNCTION(6, "CONN_BT_TXD"), + MTK_FUNCTION(7, "PTA_TXD") + ), + MTK_PIN( + 30, "GPIO30", + MTK_EINT_FUNCTION(0, 30), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO30"), + MTK_FUNCTION(1, "I2SIN2_LRCK"), + MTK_FUNCTION(2, "TP_URXD1_VCORE"), + MTK_FUNCTION(3, "MD_URXD0"), + MTK_FUNCTION(4, "SSPM_URXD_AO_VCORE"), + MTK_FUNCTION(5, "MD32_1_RXD"), + MTK_FUNCTION(7, "PTA_RXD") + ), + MTK_PIN( + 31, "GPIO31", + MTK_EINT_FUNCTION(0, 31), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO31"), + MTK_FUNCTION(1, "I2SOUT2_DO"), + MTK_FUNCTION(2, "TP_UTXD2_VCORE"), + MTK_FUNCTION(3, "MD_UTXD1"), + MTK_FUNCTION(4, "HFRP_UTXD1"), + MTK_FUNCTION(5, "MD32_0_TXD"), + MTK_FUNCTION(6, "CONN_WIFI_TXD"), + MTK_FUNCTION(7, "CONN_BGF_UART0_TXD") + ), + MTK_PIN( + 32, "GPIO32", + MTK_EINT_FUNCTION(0, 32), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO32"), + MTK_FUNCTION(1, "I2SIN2_DI"), + MTK_FUNCTION(2, "TP_URXD2_VCORE"), + MTK_FUNCTION(3, "MD_URXD1"), + MTK_FUNCTION(4, "HFRP_URXD1"), + MTK_FUNCTION(5, "MD32_0_RXD"), + MTK_FUNCTION(7, "CONN_BGF_UART0_RXD") + ), + MTK_PIN( + 33, "GPIO33", + MTK_EINT_FUNCTION(0, 33), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO33"), + MTK_FUNCTION(1, "ANT_SEL0"), + MTK_FUNCTION(3, "GPS_L1_ELNA_EN"), + MTK_FUNCTION(4, "SCL1"), + MTK_FUNCTION(5, "CONN_BPI_BUS18_ANT1"), + MTK_FUNCTION(6, "MD_UCTS0") + ), + MTK_PIN( + 34, "GPIO34", + MTK_EINT_FUNCTION(0, 34), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO34"), + MTK_FUNCTION(1, "ANT_SEL1"), + MTK_FUNCTION(3, "GPS_L5_ELNA_EN"), + MTK_FUNCTION(4, "SDA1"), + MTK_FUNCTION(5, "CONN_BPI_BUS19_ANT2"), + MTK_FUNCTION(6, "MD_URTS0") + ), + MTK_PIN( + 35, "GPIO35", + MTK_EINT_FUNCTION(0, 35), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO35"), + MTK_FUNCTION(1, "ANT_SEL2"), + MTK_FUNCTION(2, "SSPM_JTAG_TCK_VCORE"), + MTK_FUNCTION(3, "UDI_TCK"), + MTK_FUNCTION(5, "CONN_BPI_BUS20_ANT3"), + MTK_FUNCTION(6, "MD_UCTS1") + ), + MTK_PIN( + 36, "GPIO36", + MTK_EINT_FUNCTION(0, 36), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO36"), + MTK_FUNCTION(1, "ANT_SEL3"), + MTK_FUNCTION(2, "SSPM_JTAG_TRSTN_VCORE"), + MTK_FUNCTION(3, "UDI_NTRST"), + MTK_FUNCTION(5, "CONN_BPI_BUS21_ANT4"), + MTK_FUNCTION(6, "MD_URTS1") + ), + MTK_PIN( + 37, "GPIO37", + MTK_EINT_FUNCTION(0, 37), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO37"), + MTK_FUNCTION(1, "ANT_SEL4"), + MTK_FUNCTION(2, "SSPM_JTAG_TDI_VCORE"), + MTK_FUNCTION(3, "UDI_TDI"), + MTK_FUNCTION(6, "TP_UCTS1_VCORE") + ), + MTK_PIN( + 38, "GPIO38", + MTK_EINT_FUNCTION(0, 38), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO38"), + MTK_FUNCTION(1, "ANT_SEL5"), + MTK_FUNCTION(2, "SSPM_JTAG_TMS_VCORE"), + MTK_FUNCTION(3, "UDI_TMS"), + MTK_FUNCTION(6, "TP_URTS1_VCORE") + ), + MTK_PIN( + 39, "GPIO39", + MTK_EINT_FUNCTION(0, 39), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO39"), + MTK_FUNCTION(1, "ANT_SEL6"), + MTK_FUNCTION(2, "SSPM_JTAG_TDO_VCORE"), + MTK_FUNCTION(3, "UDI_TDO"), + MTK_FUNCTION(5, "CLKM3") + ), + MTK_PIN( + 40, "GPIO40", + MTK_EINT_FUNCTION(0, 40), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO40"), + MTK_FUNCTION(1, "ANT_SEL7"), + MTK_FUNCTION(2, "PMSR_SMAP"), + MTK_FUNCTION(3, "CONN_TCXOENA_REQ"), + MTK_FUNCTION(4, "CONN_WIFI_TXD"), + MTK_FUNCTION(5, "GPS_PPS") + ), + MTK_PIN( + 41, "GPIO41", + MTK_EINT_FUNCTION(0, 41), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO41"), + MTK_FUNCTION(1, "I2SIN1_MCK"), + MTK_FUNCTION(2, "IDDIG"), + MTK_FUNCTION(3, "GPS_PPS"), + MTK_FUNCTION(4, "HFRP_UCTS1"), + MTK_FUNCTION(5, "TP_UCTS2_VCORE"), + MTK_FUNCTION(6, "ANT_SEL8"), + MTK_FUNCTION(7, "DBG_MON_B1") + ), + MTK_PIN( + 42, "GPIO42", + MTK_EINT_FUNCTION(0, 42), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO42"), + MTK_FUNCTION(1, "I2SIN1_BCK"), + MTK_FUNCTION(2, "I2SIN4_BCK"), + MTK_FUNCTION(4, "HFRP_URTS1"), + MTK_FUNCTION(5, "TP_URTS2_VCORE"), + MTK_FUNCTION(6, "ANT_SEL9"), + MTK_FUNCTION(7, "DBG_MON_B2") + ), + MTK_PIN( + 43, "GPIO43", + MTK_EINT_FUNCTION(0, 43), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO43"), + MTK_FUNCTION(1, "I2SIN1_LRCK"), + MTK_FUNCTION(2, "I2SIN4_LRCK"), + MTK_FUNCTION(6, "ANT_SEL10"), + MTK_FUNCTION(7, "DBG_MON_B3") + ), + MTK_PIN( + 44, "GPIO44", + MTK_EINT_FUNCTION(0, 44), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO44"), + MTK_FUNCTION(1, "I2SOUT1_DO"), + MTK_FUNCTION(2, "I2SOUT4_DATA0"), + MTK_FUNCTION(6, "ANT_SEL11"), + MTK_FUNCTION(7, "DBG_MON_B4") + ), + MTK_PIN( + 45, "GPIO45", + MTK_EINT_FUNCTION(0, 45), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO45"), + MTK_FUNCTION(1, "I2SIN1_DI"), + MTK_FUNCTION(2, "I2SIN4_DATA0"), + MTK_FUNCTION(5, "AGPS_SYNC"), + MTK_FUNCTION(6, "ANT_SEL12"), + MTK_FUNCTION(7, "DBG_MON_B5") + ), + MTK_PIN( + 46, "GPIO46", + MTK_EINT_FUNCTION(0, 46), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO46"), + MTK_FUNCTION(1, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(2, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(3, "SRCLKENAI0"), + MTK_FUNCTION(5, "SSPM_UTXD_AO_VLP"), + MTK_FUNCTION(6, "MD_MCIF_UTXD0"), + MTK_FUNCTION(7, "DBG_MON_B6") + ), + MTK_PIN( + 47, "GPIO47", + MTK_EINT_FUNCTION(0, 47), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO47"), + MTK_FUNCTION(1, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(2, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(3, "SRCLKENAI1"), + MTK_FUNCTION(4, "SRCLKENA1"), + MTK_FUNCTION(5, "SSPM_URXD_AO_VLP"), + MTK_FUNCTION(6, "MD_MCIF_URXD0"), + MTK_FUNCTION(7, "DBG_MON_B7") + ), + MTK_PIN( + 48, "GPIO48", + MTK_EINT_FUNCTION(0, 48), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO48"), + MTK_FUNCTION(1, "UTXD0"), + MTK_FUNCTION(3, "MD_UTXD1"), + MTK_FUNCTION(4, "HFRP_UTXD1"), + MTK_FUNCTION(5, "MD32_0_TXD") + ), + MTK_PIN( + 49, "GPIO49", + MTK_EINT_FUNCTION(0, 49), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO49"), + MTK_FUNCTION(1, "URXD0"), + MTK_FUNCTION(3, "MD_URXD1"), + MTK_FUNCTION(4, "HFRP_URXD1"), + MTK_FUNCTION(5, "MD32_0_RXD") + ), + MTK_PIN( + 50, "GPIO50", + MTK_EINT_FUNCTION(0, 50), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO50"), + MTK_FUNCTION(1, "MD_UTXD0"), + MTK_FUNCTION(2, "TP_UTXD1_VLP"), + MTK_FUNCTION(3, "CONN_BGF_UART0_TXD"), + MTK_FUNCTION(4, "SSPM_UTXD_AO_VLP"), + MTK_FUNCTION(5, "MD_MCIF_UTXD0"), + MTK_FUNCTION(6, "TP_UTXD2_VLP"), + MTK_FUNCTION(7, "UTXD1") + ), + MTK_PIN( + 51, "GPIO51", + MTK_EINT_FUNCTION(0, 51), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO51"), + MTK_FUNCTION(1, "MD_URXD0"), + MTK_FUNCTION(2, "TP_URXD1_VLP"), + MTK_FUNCTION(3, "CONN_BGF_UART0_RXD"), + MTK_FUNCTION(4, "SSPM_URXD_AO_VLP"), + MTK_FUNCTION(5, "MD_MCIF_URXD0"), + MTK_FUNCTION(6, "TP_URXD2_VLP"), + MTK_FUNCTION(7, "URXD1") + ), + MTK_PIN( + 52, "GPIO52", + MTK_EINT_FUNCTION(0, 52), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO52"), + MTK_FUNCTION(1, "KPROW0"), + MTK_FUNCTION(2, "CMFLASH0"), + MTK_FUNCTION(3, "SDA12"), + MTK_FUNCTION(4, "DSI_TE1") + ), + MTK_PIN( + 53, "GPIO53", + MTK_EINT_FUNCTION(0, 53), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO53"), + MTK_FUNCTION(1, "KPROW1"), + MTK_FUNCTION(2, "CMFLASH1"), + MTK_FUNCTION(3, "SCL12"), + MTK_FUNCTION(4, "LCM_RST1"), + MTK_FUNCTION(6, "EXTIF0_ACT") + ), + MTK_PIN( + 54, "GPIO54", + MTK_EINT_FUNCTION(0, 54), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO54"), + MTK_FUNCTION(1, "KPCOL0_VLP"), + MTK_FUNCTION(7, "KPCOL0_VLP") + ), + MTK_PIN( + 55, "GPIO55", + MTK_EINT_FUNCTION(0, 55), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO55"), + MTK_FUNCTION(1, "KPCOL1"), + MTK_FUNCTION(3, "SDA12"), + MTK_FUNCTION(4, "DISP_PWM1"), + MTK_FUNCTION(7, "JTRSTN_SEL1_VCORE") + ), + MTK_PIN( + 56, "GPIO56", + MTK_EINT_FUNCTION(0, 56), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO56"), + MTK_FUNCTION(1, "SPI0_CLK"), + MTK_FUNCTION(7, "JTCK_SEL1_VCORE") + ), + MTK_PIN( + 57, "GPIO57", + MTK_EINT_FUNCTION(0, 57), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO57"), + MTK_FUNCTION(1, "SPI0_CSB"), + MTK_FUNCTION(7, "JTMS_SEL1_VCORE") + ), + MTK_PIN( + 58, "GPIO58", + MTK_EINT_FUNCTION(0, 58), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO58"), + MTK_FUNCTION(1, "SPI0_MO"), + MTK_FUNCTION(7, "JTDO_SEL1_VCORE") + ), + MTK_PIN( + 59, "GPIO59", + MTK_EINT_FUNCTION(0, 59), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO59"), + MTK_FUNCTION(1, "SPI0_MI"), + MTK_FUNCTION(7, "JTDI_SEL1_VCORE") + ), + MTK_PIN( + 60, "GPIO60", + MTK_EINT_FUNCTION(0, 60), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO60"), + MTK_FUNCTION(1, "SCP_SPI1_CK"), + MTK_FUNCTION(2, "SPI1_CLK"), + MTK_FUNCTION(4, "SCP_SCL3"), + MTK_FUNCTION(5, "TP_GPIO0_AO"), + MTK_FUNCTION(6, "UTXD0"), + MTK_FUNCTION(7, "TP_UTXD2_VLP") + ), + MTK_PIN( + 61, "GPIO61", + MTK_EINT_FUNCTION(0, 61), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO61"), + MTK_FUNCTION(1, "SCP_SPI1_CS"), + MTK_FUNCTION(2, "SPI1_CSB"), + MTK_FUNCTION(5, "TP_GPIO1_AO"), + MTK_FUNCTION(6, "URXD0"), + MTK_FUNCTION(7, "TP_URXD2_VLP") + ), + MTK_PIN( + 62, "GPIO62", + MTK_EINT_FUNCTION(0, 62), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO62"), + MTK_FUNCTION(1, "SCP_SPI1_MO"), + MTK_FUNCTION(2, "SPI1_MO"), + MTK_FUNCTION(3, "SCP_SCL3"), + MTK_FUNCTION(4, "SCP_SDA3"), + MTK_FUNCTION(5, "TP_GPIO2_AO"), + MTK_FUNCTION(7, "DBG_MON_B29") + ), + MTK_PIN( + 63, "GPIO63", + MTK_EINT_FUNCTION(0, 63), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO63"), + MTK_FUNCTION(1, "SCP_SPI1_MI"), + MTK_FUNCTION(2, "SPI1_MI"), + MTK_FUNCTION(3, "SCP_SDA3"), + MTK_FUNCTION(5, "TP_GPIO3_AO"), + MTK_FUNCTION(7, "DBG_MON_B30") + ), + MTK_PIN( + 64, "GPIO64", + MTK_EINT_FUNCTION(0, 64), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO64"), + MTK_FUNCTION(1, "SCP_SPI2_CK"), + MTK_FUNCTION(2, "SPI2_CLK"), + MTK_FUNCTION(4, "SCP_SCL2"), + MTK_FUNCTION(5, "TP_GPIO4_AO") + ), + MTK_PIN( + 65, "GPIO65", + MTK_EINT_FUNCTION(0, 65), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO65"), + MTK_FUNCTION(1, "SCP_SPI2_CS"), + MTK_FUNCTION(2, "SPI2_CSB"), + MTK_FUNCTION(5, "TP_GPIO5_AO"), + MTK_FUNCTION(7, "DBG_MON_B31") + ), + MTK_PIN( + 66, "GPIO66", + MTK_EINT_FUNCTION(0, 66), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO66"), + MTK_FUNCTION(1, "SCP_SPI2_MO"), + MTK_FUNCTION(2, "SPI2_MO"), + MTK_FUNCTION(3, "SCP_SCL2"), + MTK_FUNCTION(4, "SCP_SDA2"), + MTK_FUNCTION(5, "TP_GPIO6_AO") + ), + MTK_PIN( + 67, "GPIO67", + MTK_EINT_FUNCTION(0, 67), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO67"), + MTK_FUNCTION(1, "SCP_SPI2_MI"), + MTK_FUNCTION(2, "SPI2_MI"), + MTK_FUNCTION(3, "SCP_SDA2"), + MTK_FUNCTION(5, "TP_GPIO7_AO") + ), + MTK_PIN( + 68, "GPIO68", + MTK_EINT_FUNCTION(0, 68), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO68"), + MTK_FUNCTION(1, "SCP_SPI3_CK"), + MTK_FUNCTION(2, "SPI3_CLK"), + MTK_FUNCTION(3, "MD_INT4"), + MTK_FUNCTION(4, "SCP_SCL4"), + MTK_FUNCTION(5, "TP_GPIO8_AO"), + MTK_FUNCTION(7, "DBG_MON_A19") + ), + MTK_PIN( + 69, "GPIO69", + MTK_EINT_FUNCTION(0, 69), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO69"), + MTK_FUNCTION(1, "SCP_SPI3_CS"), + MTK_FUNCTION(2, "SPI3_CSB"), + MTK_FUNCTION(3, "MD_INT3"), + MTK_FUNCTION(5, "TP_GPIO9_AO"), + MTK_FUNCTION(7, "DBG_MON_A20") + ), + MTK_PIN( + 70, "GPIO70", + MTK_EINT_FUNCTION(0, 70), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO70"), + MTK_FUNCTION(1, "SCP_SPI3_MO"), + MTK_FUNCTION(2, "SPI3_MO"), + MTK_FUNCTION(3, "SCP_SCL4"), + MTK_FUNCTION(4, "SCP_SDA4"), + MTK_FUNCTION(5, "TP_GPIO10_AO"), + MTK_FUNCTION(7, "DBG_MON_A21") + ), + MTK_PIN( + 71, "GPIO71", + MTK_EINT_FUNCTION(0, 71), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO71"), + MTK_FUNCTION(1, "SCP_SPI3_MI"), + MTK_FUNCTION(2, "SPI3_MI"), + MTK_FUNCTION(3, "SCP_SDA4"), + MTK_FUNCTION(4, "MD_INT0"), + MTK_FUNCTION(5, "TP_GPIO11_AO"), + MTK_FUNCTION(7, "DBG_MON_A22") + ), + MTK_PIN( + 72, "GPIO72", + MTK_EINT_FUNCTION(0, 72), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO72"), + MTK_FUNCTION(1, "SPI5_CLK"), + MTK_FUNCTION(2, "SCP_SPI0_CK"), + MTK_FUNCTION(3, "UCTS2"), + MTK_FUNCTION(4, "MBISTREADEN_TRIGGER"), + MTK_FUNCTION(5, "TP_GPIO12_AO"), + MTK_FUNCTION(6, "EXTIF0_ACT"), + MTK_FUNCTION(7, "DAP_SONIC_SWCK") + ), + MTK_PIN( + 73, "GPIO73", + MTK_EINT_FUNCTION(0, 73), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO73"), + MTK_FUNCTION(1, "SPI5_CSB"), + MTK_FUNCTION(2, "SCP_SPI0_CS"), + MTK_FUNCTION(3, "URTS2"), + MTK_FUNCTION(4, "MBISTWRITEEN_TRIGGER"), + MTK_FUNCTION(5, "TP_GPIO13_AO"), + MTK_FUNCTION(6, "EXTIF0_PRI"), + MTK_FUNCTION(7, "DAP_SONIC_SWD") + ), + MTK_PIN( + 74, "GPIO74", + MTK_EINT_FUNCTION(0, 74), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO74"), + MTK_FUNCTION(1, "SPI5_MO"), + MTK_FUNCTION(2, "SCP_SPI0_MO"), + MTK_FUNCTION(3, "UTXD2"), + MTK_FUNCTION(4, "TP_UTXD2_VCORE"), + MTK_FUNCTION(5, "TP_GPIO14_AO"), + MTK_FUNCTION(6, "EXTIF0_GNT_B"), + MTK_FUNCTION(7, "DAP_MD32_SWCK") + ), + MTK_PIN( + 75, "GPIO75", + MTK_EINT_FUNCTION(0, 75), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO75"), + MTK_FUNCTION(1, "SPI5_MI"), + MTK_FUNCTION(2, "SCP_SPI0_MI"), + MTK_FUNCTION(3, "URXD2"), + MTK_FUNCTION(4, "TP_URXD2_VCORE"), + MTK_FUNCTION(5, "TP_GPIO15_AO"), + MTK_FUNCTION(7, "DAP_MD32_SWD") + ), + MTK_PIN( + 76, "GPIO76", + MTK_EINT_FUNCTION(0, 76), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO76"), + MTK_FUNCTION(1, "AP_GOOD"), + MTK_FUNCTION(3, "CONN_WIFI_TXD"), + MTK_FUNCTION(4, "GPS_PPS"), + MTK_FUNCTION(5, "PMSR_SMAP"), + MTK_FUNCTION(6, "AGPS_SYNC") + ), + MTK_PIN( + 77, "GPIO77", + MTK_EINT_FUNCTION(0, 77), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO77"), + MTK_FUNCTION(1, "MSDC1_CLK"), + MTK_FUNCTION(2, "MD1_SIM2_SCLK"), + MTK_FUNCTION(3, "UDI_TCK"), + MTK_FUNCTION(4, "CONN_DSP_JCK"), + MTK_FUNCTION(6, "TSFDC_EN"), + MTK_FUNCTION(7, "SSPM_JTAG_TCK_VCORE") + ), + MTK_PIN( + 78, "GPIO78", + MTK_EINT_FUNCTION(0, 78), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO78"), + MTK_FUNCTION(1, "MSDC1_CMD"), + MTK_FUNCTION(2, "CONN_WF_MCU_AICE_TMSC"), + MTK_FUNCTION(3, "UDI_TMS"), + MTK_FUNCTION(4, "CONN_DSP_JMS"), + MTK_FUNCTION(6, "TSFDC_VCO_RST"), + MTK_FUNCTION(7, "SSPM_JTAG_TMS_VCORE") + ), + MTK_PIN( + 79, "GPIO79", + MTK_EINT_FUNCTION(0, 79), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO79"), + MTK_FUNCTION(1, "MSDC1_DAT0"), + MTK_FUNCTION(2, "MD1_SIM2_SRST"), + MTK_FUNCTION(3, "UDI_TDI"), + MTK_FUNCTION(4, "CONN_DSP_JDI"), + MTK_FUNCTION(6, "TSFDC_TSSEL2"), + MTK_FUNCTION(7, "SSPM_JTAG_TDI_VCORE") + ), + MTK_PIN( + 80, "GPIO80", + MTK_EINT_FUNCTION(0, 80), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO80"), + MTK_FUNCTION(1, "MSDC1_DAT1"), + MTK_FUNCTION(2, "MD1_SIM2_SIO"), + MTK_FUNCTION(3, "UDI_TDO"), + MTK_FUNCTION(4, "CONN_DSP_JDO"), + MTK_FUNCTION(6, "TSFDC_TSSEL1"), + MTK_FUNCTION(7, "SSPM_JTAG_TDO_VCORE") + ), + MTK_PIN( + 81, "GPIO81", + MTK_EINT_FUNCTION(0, 81), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO81"), + MTK_FUNCTION(1, "MSDC1_DAT2"), + MTK_FUNCTION(2, "CONN_WF_MCU_AICE_TCKC"), + MTK_FUNCTION(3, "UDI_NTRST"), + MTK_FUNCTION(4, "CONN_BGF_MCU_AICE_TCKC"), + MTK_FUNCTION(5, "MIPI3_D_SDATA"), + MTK_FUNCTION(6, "TSFDC_TSSEL0"), + MTK_FUNCTION(7, "SSPM_JTAG_TRSTN_VCORE") + ), + MTK_PIN( + 82, "GPIO82", + MTK_EINT_FUNCTION(0, 82), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO82"), + MTK_FUNCTION(1, "MSDC1_DAT3"), + MTK_FUNCTION(3, "CONN_BGF_MCU_AICE_TMSC"), + MTK_FUNCTION(4, "CONN_DSP_JINTP"), + MTK_FUNCTION(5, "MIPI3_D_SCLK"), + MTK_FUNCTION(6, "TSFDC_RCK_SELB") + ), + MTK_PIN( + 83, "GPIO83", + MTK_EINT_FUNCTION(0, 83), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO83"), + MTK_FUNCTION(1, "MD1_SIM1_SCLK"), + MTK_FUNCTION(6, "TSFDC_26M") + ), + MTK_PIN( + 84, "GPIO84", + MTK_EINT_FUNCTION(0, 84), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO84"), + MTK_FUNCTION(1, "MD1_SIM1_SRST"), + MTK_FUNCTION(3, "SPM_JTAG_TCK_VCORE"), + MTK_FUNCTION(4, "APU_JTAG_TCK"), + MTK_FUNCTION(6, "TSFDC_SDO"), + MTK_FUNCTION(7, "CONN_DSP_L5_JCK") + ), + MTK_PIN( + 85, "GPIO85", + MTK_EINT_FUNCTION(0, 85), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO85"), + MTK_FUNCTION(1, "MD1_SIM1_SIO"), + MTK_FUNCTION(3, "SPM_JTAG_TRSTN_VCORE"), + MTK_FUNCTION(4, "APU_JTAG_TRST"), + MTK_FUNCTION(6, "TSFDC_FOUT"), + MTK_FUNCTION(7, "CONN_DSP_L5_JINTP") + ), + MTK_PIN( + 86, "GPIO86", + MTK_EINT_FUNCTION(0, 86), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO86"), + MTK_FUNCTION(1, "MD1_SIM2_SCLK"), + MTK_FUNCTION(3, "SPM_JTAG_TDI_VCORE"), + MTK_FUNCTION(4, "APU_JTAG_TDI"), + MTK_FUNCTION(6, "TSFDC_SCK"), + MTK_FUNCTION(7, "CONN_DSP_L5_JDI") + ), + MTK_PIN( + 87, "GPIO87", + MTK_EINT_FUNCTION(0, 87), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO87"), + MTK_FUNCTION(1, "MD1_SIM2_SRST"), + MTK_FUNCTION(3, "SPM_JTAG_TMS_VCORE"), + MTK_FUNCTION(4, "APU_JTAG_TMS"), + MTK_FUNCTION(6, "TSFDC_SDI"), + MTK_FUNCTION(7, "CONN_DSP_L5_JMS") + ), + MTK_PIN( + 88, "GPIO88", + MTK_EINT_FUNCTION(0, 88), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO88"), + MTK_FUNCTION(1, "MD1_SIM2_SIO"), + MTK_FUNCTION(3, "SPM_JTAG_TDO_VCORE"), + MTK_FUNCTION(4, "APU_JTAG_TDO"), + MTK_FUNCTION(6, "TSFDC_SCF"), + MTK_FUNCTION(7, "CONN_DSP_L5_JDO") + ), + MTK_PIN( + 89, "GPIO89", + MTK_EINT_FUNCTION(0, 89), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO89"), + MTK_FUNCTION(1, "DSI_TE"), + MTK_FUNCTION(7, "DBG_MON_B8") + ), + MTK_PIN( + 90, "GPIO90", + MTK_EINT_FUNCTION(0, 90), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO90"), + MTK_FUNCTION(1, "LCM_RST"), + MTK_FUNCTION(7, "DBG_MON_B9") + ), + MTK_PIN( + 91, "GPIO91", + MTK_EINT_FUNCTION(0, 91), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO91"), + MTK_FUNCTION(1, "DISP_PWM"), + MTK_FUNCTION(7, "DBG_MON_B10") + ), + MTK_PIN( + 92, "GPIO92", + MTK_EINT_FUNCTION(0, 92), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO92"), + MTK_FUNCTION(1, "CMMCLK0"), + MTK_FUNCTION(7, "DBG_MON_A23") + ), + MTK_PIN( + 93, "GPIO93", + MTK_EINT_FUNCTION(0, 93), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO93"), + MTK_FUNCTION(1, "CMMCLK1"), + MTK_FUNCTION(7, "DBG_MON_A24") + ), + MTK_PIN( + 94, "GPIO94", + MTK_EINT_FUNCTION(0, 94), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO94"), + MTK_FUNCTION(1, "CMMCLK2"), + MTK_FUNCTION(7, "DBG_MON_A25") + ), + MTK_PIN( + 95, "GPIO95", + MTK_EINT_FUNCTION(0, 95), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO95"), + MTK_FUNCTION(1, "CMMCLK3"), + MTK_FUNCTION(5, "MD32_1_TXD"), + MTK_FUNCTION(6, "PTA_TXD"), + MTK_FUNCTION(7, "DBG_MON_A26") + ), + MTK_PIN( + 96, "GPIO96", + MTK_EINT_FUNCTION(0, 96), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO96"), + MTK_FUNCTION(1, "CMMCLK4"), + MTK_FUNCTION(5, "MD32_1_RXD"), + MTK_FUNCTION(6, "PTA_RXD"), + MTK_FUNCTION(7, "DBG_MON_A27") + ), + MTK_PIN( + 97, "GPIO97", + MTK_EINT_FUNCTION(0, 97), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO97"), + MTK_FUNCTION(1, "MD_UCNT_A_TGL") + ), + MTK_PIN( + 98, "GPIO98", + MTK_EINT_FUNCTION(0, 98), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO98"), + MTK_FUNCTION(1, "DIGRF_IRQ") + ), + MTK_PIN( + 99, "GPIO99", + MTK_EINT_FUNCTION(0, 99), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO99"), + MTK_FUNCTION(1, "BPI_BUS0"), + MTK_FUNCTION(4, "MFG_TSFDC_EN"), + MTK_FUNCTION(6, "ANT_SEL0"), + MTK_FUNCTION(7, "DBG_MON_B11") + ), + MTK_PIN( + 100, "GPIO100", + MTK_EINT_FUNCTION(0, 100), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO100"), + MTK_FUNCTION(1, "BPI_BUS1"), + MTK_FUNCTION(4, "MFG_TSFDC_VCO_RST"), + MTK_FUNCTION(6, "ANT_SEL1"), + MTK_FUNCTION(7, "DBG_MON_B12") + ), + MTK_PIN( + 101, "GPIO101", + MTK_EINT_FUNCTION(0, 101), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO101"), + MTK_FUNCTION(1, "BPI_BUS2"), + MTK_FUNCTION(3, "DMIC1_CLK"), + MTK_FUNCTION(4, "MFG_TSFDC_TSSEL2"), + MTK_FUNCTION(6, "ANT_SEL2"), + MTK_FUNCTION(7, "DBG_MON_B13") + ), + MTK_PIN( + 102, "GPIO102", + MTK_EINT_FUNCTION(0, 102), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO102"), + MTK_FUNCTION(1, "BPI_BUS3"), + MTK_FUNCTION(3, "DMIC1_DAT"), + MTK_FUNCTION(4, "MFG_TSFDC_TSSEL1"), + MTK_FUNCTION(6, "ANT_SEL3"), + MTK_FUNCTION(7, "DBG_MON_B14") + ), + MTK_PIN( + 103, "GPIO103", + MTK_EINT_FUNCTION(0, 103), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO103"), + MTK_FUNCTION(1, "BPI_BUS4"), + MTK_FUNCTION(4, "MFG_TSFDC_TSSEL0"), + MTK_FUNCTION(6, "ANT_SEL4"), + MTK_FUNCTION(7, "DBG_MON_B15") + ), + MTK_PIN( + 104, "GPIO104", + MTK_EINT_FUNCTION(0, 104), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO104"), + MTK_FUNCTION(1, "BPI_BUS5"), + MTK_FUNCTION(4, "MFG_TSFDC_RCK_SELB"), + MTK_FUNCTION(6, "ANT_SEL5"), + MTK_FUNCTION(7, "DBG_MON_B16") + ), + MTK_PIN( + 105, "GPIO105", + MTK_EINT_FUNCTION(0, 105), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO105"), + MTK_FUNCTION(1, "BPI_BUS6"), + MTK_FUNCTION(2, "CONN_BPI_BUS6"), + MTK_FUNCTION(6, "ANT_SEL6"), + MTK_FUNCTION(7, "DBG_MON_B17") + ), + MTK_PIN( + 106, "GPIO106", + MTK_EINT_FUNCTION(0, 106), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO106"), + MTK_FUNCTION(1, "BPI_BUS7"), + MTK_FUNCTION(2, "CONN_BPI_BUS7"), + MTK_FUNCTION(4, "MFG_TSFDC_SDO"), + MTK_FUNCTION(5, "AUD_DAC_26M_CLK"), + MTK_FUNCTION(6, "ANT_SEL7"), + MTK_FUNCTION(7, "DBG_MON_B18") + ), + MTK_PIN( + 107, "GPIO107", + MTK_EINT_FUNCTION(0, 107), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO107"), + MTK_FUNCTION(1, "BPI_BUS8"), + MTK_FUNCTION(2, "CONN_BPI_BUS8"), + MTK_FUNCTION(4, "MFG_TSFDC_FOUT"), + MTK_FUNCTION(5, "I2SOUT4_DATA0"), + MTK_FUNCTION(6, "ANT_SEL8"), + MTK_FUNCTION(7, "DBG_MON_B19") + ), + MTK_PIN( + 108, "GPIO108", + MTK_EINT_FUNCTION(0, 108), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO108"), + MTK_FUNCTION(1, "BPI_BUS9"), + MTK_FUNCTION(2, "CONN_BPI_BUS9"), + MTK_FUNCTION(5, "I2SOUT4_DATA1"), + MTK_FUNCTION(6, "ANT_SEL9"), + MTK_FUNCTION(7, "DBG_MON_B20") + ), + MTK_PIN( + 109, "GPIO109", + MTK_EINT_FUNCTION(0, 109), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO109"), + MTK_FUNCTION(1, "BPI_BUS10"), + MTK_FUNCTION(2, "CONN_BPI_BUS10"), + MTK_FUNCTION(5, "I2SOUT4_DATA2"), + MTK_FUNCTION(6, "ANT_SEL10"), + MTK_FUNCTION(7, "DBG_MON_B21") + ), + MTK_PIN( + 110, "GPIO110", + MTK_EINT_FUNCTION(0, 110), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO110"), + MTK_FUNCTION(1, "BPI_BUS11"), + MTK_FUNCTION(2, "CONN_BPI_BUS11_OLAT0"), + MTK_FUNCTION(5, "I2SOUT4_DATA3"), + MTK_FUNCTION(6, "ANT_SEL11"), + MTK_FUNCTION(7, "DBG_MON_B22") + ), + MTK_PIN( + 111, "GPIO111", + MTK_EINT_FUNCTION(0, 111), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO111"), + MTK_FUNCTION(1, "BPI_BUS12"), + MTK_FUNCTION(2, "CONN_BPI_BUS12_OLAT1"), + MTK_FUNCTION(3, "CLKM0"), + MTK_FUNCTION(5, "I2SIN4_BCK"), + MTK_FUNCTION(6, "ANT_SEL12"), + MTK_FUNCTION(7, "DBG_MON_B23") + ), + MTK_PIN( + 112, "GPIO112", + MTK_EINT_FUNCTION(0, 112), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO112"), + MTK_FUNCTION(1, "BPI_BUS13"), + MTK_FUNCTION(2, "CONN_BPI_BUS13_OLAT2"), + MTK_FUNCTION(3, "CLKM1"), + MTK_FUNCTION(5, "I2SIN4_DATA0"), + MTK_FUNCTION(6, "ANT_SEL13"), + MTK_FUNCTION(7, "DBG_MON_B24") + ), + MTK_PIN( + 113, "GPIO113", + MTK_EINT_FUNCTION(0, 113), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO113"), + MTK_FUNCTION(1, "BPI_BUS14"), + MTK_FUNCTION(2, "CONN_BPI_BUS14_OLAT3"), + MTK_FUNCTION(3, "CLKM2"), + MTK_FUNCTION(5, "I2SIN4_DATA1"), + MTK_FUNCTION(6, "ANT_SEL14"), + MTK_FUNCTION(7, "DBG_MON_B25") + ), + MTK_PIN( + 114, "GPIO114", + MTK_EINT_FUNCTION(0, 114), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO114"), + MTK_FUNCTION(1, "BPI_BUS15"), + MTK_FUNCTION(2, "CONN_BPI_BUS15_OLAT4"), + MTK_FUNCTION(3, "CLKM3"), + MTK_FUNCTION(5, "I2SIN4_DATA2"), + MTK_FUNCTION(6, "ANT_SEL15"), + MTK_FUNCTION(7, "DBG_MON_B26") + ), + MTK_PIN( + 115, "GPIO115", + MTK_EINT_FUNCTION(0, 115), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO115"), + MTK_FUNCTION(1, "BPI_BUS16"), + MTK_FUNCTION(2, "CONN_BPI_BUS16_OLAT5"), + MTK_FUNCTION(5, "I2SIN4_DATA3"), + MTK_FUNCTION(6, "ANT_SEL16"), + MTK_FUNCTION(7, "DBG_MON_B27") + ), + MTK_PIN( + 116, "GPIO116", + MTK_EINT_FUNCTION(0, 116), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO116"), + MTK_FUNCTION(1, "BPI_BUS17"), + MTK_FUNCTION(2, "CONN_BPI_BUS17_ANT0"), + MTK_FUNCTION(5, "I2SIN4_LRCK"), + MTK_FUNCTION(6, "ANT_SEL17"), + MTK_FUNCTION(7, "DBG_MON_B28") + ), + MTK_PIN( + 117, "GPIO117", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO117"), + MTK_FUNCTION(1, "MIPI0_D_SCLK"), + MTK_FUNCTION(2, "CONN_MIPI0_SCLK"), + MTK_FUNCTION(3, "BPI_BUS18"), + MTK_FUNCTION(6, "ANT_SEL18") + ), + MTK_PIN( + 118, "GPIO118", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO118"), + MTK_FUNCTION(1, "MIPI0_D_SDATA"), + MTK_FUNCTION(2, "CONN_MIPI0_SDATA"), + MTK_FUNCTION(3, "BPI_BUS19"), + MTK_FUNCTION(6, "ANT_SEL19") + ), + MTK_PIN( + 119, "GPIO119", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO119"), + MTK_FUNCTION(1, "MIPI1_D_SCLK"), + MTK_FUNCTION(2, "CONN_MIPI1_SCLK"), + MTK_FUNCTION(3, "BPI_BUS20"), + MTK_FUNCTION(6, "ANT_SEL20") + ), + MTK_PIN( + 120, "GPIO120", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO120"), + MTK_FUNCTION(1, "MIPI1_D_SDATA"), + MTK_FUNCTION(2, "CONN_MIPI1_SDATA"), + MTK_FUNCTION(3, "BPI_BUS21"), + MTK_FUNCTION(6, "ANT_SEL21") + ), + MTK_PIN( + 121, "GPIO121", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO121"), + MTK_FUNCTION(1, "MIPI2_D_SCLK"), + MTK_FUNCTION(2, "MIPI4_D_SCLK"), + MTK_FUNCTION(3, "BPI_BUS22"), + MTK_FUNCTION(6, "MD_GPS_L1_BLANK") + ), + MTK_PIN( + 122, "GPIO122", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO122"), + MTK_FUNCTION(1, "MIPI2_D_SDATA"), + MTK_FUNCTION(2, "MIPI4_D_SDATA"), + MTK_FUNCTION(3, "BPI_BUS23"), + MTK_FUNCTION(6, "MD_GPS_L5_BLANK") + ), + MTK_PIN( + 123, "GPIO123", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO123"), + MTK_FUNCTION(1, "MIPI_M_SCLK") + ), + MTK_PIN( + 124, "GPIO124", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO124"), + MTK_FUNCTION(1, "MIPI_M_SDATA") + ), + MTK_PIN( + 125, "GPIO125", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO125"), + MTK_FUNCTION(1, "SCL0"), + MTK_FUNCTION(2, "SCP_SCL4"), + MTK_FUNCTION(3, "TP_UTXD2_VLP"), + MTK_FUNCTION(4, "TP_UCTS1_VLP"), + MTK_FUNCTION(5, "TP_GPIO4_AO"), + MTK_FUNCTION(6, "UTXD2") + ), + MTK_PIN( + 126, "GPIO126", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO126"), + MTK_FUNCTION(1, "SDA0"), + MTK_FUNCTION(2, "SCP_SDA4"), + MTK_FUNCTION(3, "TP_URXD2_VLP"), + MTK_FUNCTION(4, "TP_URTS1_VLP"), + MTK_FUNCTION(5, "TP_GPIO5_AO"), + MTK_FUNCTION(6, "URXD2") + ), + MTK_PIN( + 127, "GPIO127", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO127"), + MTK_FUNCTION(1, "SCL1"), + MTK_FUNCTION(2, "SCP_SCL5"), + MTK_FUNCTION(3, "TP_UCTS2_VLP"), + MTK_FUNCTION(4, "TP_UTXD1_VLP"), + MTK_FUNCTION(5, "TP_GPIO6_AO"), + MTK_FUNCTION(6, "MD_MCIF_UTXD0") + ), + MTK_PIN( + 128, "GPIO128", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO128"), + MTK_FUNCTION(1, "SDA1"), + MTK_FUNCTION(2, "SCP_SDA5"), + MTK_FUNCTION(3, "TP_URTS2_VLP"), + MTK_FUNCTION(4, "TP_URXD1_VLP"), + MTK_FUNCTION(5, "TP_GPIO7_AO"), + MTK_FUNCTION(6, "MD_MCIF_URXD0") + ), + MTK_PIN( + 129, "GPIO129", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO129"), + MTK_FUNCTION(1, "SCL2") + ), + MTK_PIN( + 130, "GPIO130", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO130"), + MTK_FUNCTION(1, "SDA2") + ), + MTK_PIN( + 131, "GPIO131", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO131"), + MTK_FUNCTION(1, "SCL3"), + MTK_FUNCTION(3, "TP_UTXD2_VCORE"), + MTK_FUNCTION(6, "SSPM_UTXD_AO_VCORE") + ), + MTK_PIN( + 132, "GPIO132", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO132"), + MTK_FUNCTION(1, "SDA3"), + MTK_FUNCTION(3, "TP_URXD2_VCORE"), + MTK_FUNCTION(6, "SSPM_URXD_AO_VCORE") + ), + MTK_PIN( + 133, "GPIO133", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO133"), + MTK_FUNCTION(1, "SCL4") + ), + MTK_PIN( + 134, "GPIO134", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO134"), + MTK_FUNCTION(1, "SDA4") + ), + MTK_PIN( + 135, "GPIO135", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO135"), + MTK_FUNCTION(1, "SCL5") + ), + MTK_PIN( + 136, "GPIO136", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO136"), + MTK_FUNCTION(1, "SDA5") + ), + MTK_PIN( + 137, "GPIO137", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO137"), + MTK_FUNCTION(1, "SCL6") + ), + MTK_PIN( + 138, "GPIO138", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO138"), + MTK_FUNCTION(1, "SDA6") + ), + MTK_PIN( + 139, "GPIO139", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO139"), + MTK_FUNCTION(1, "SCL7"), + MTK_FUNCTION(3, "TP_UTXD1_VCORE"), + MTK_FUNCTION(4, "MD_UTXD0"), + MTK_FUNCTION(6, "UTXD1") + ), + MTK_PIN( + 140, "GPIO140", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO140"), + MTK_FUNCTION(1, "SDA7"), + MTK_FUNCTION(3, "TP_URXD1_VCORE"), + MTK_FUNCTION(4, "MD_URXD0"), + MTK_FUNCTION(6, "URXD1") + ), + MTK_PIN( + 141, "GPIO141", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO141"), + MTK_FUNCTION(1, "SCL8") + ), + MTK_PIN( + 142, "GPIO142", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO142"), + MTK_FUNCTION(1, "SDA8") + ), + MTK_PIN( + 143, "GPIO143", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO143"), + MTK_FUNCTION(1, "SCL9"), + MTK_FUNCTION(2, "GPS_L1_ELNA_EN"), + MTK_FUNCTION(3, "HFRP_UTXD1"), + MTK_FUNCTION(4, "CONN_BGF_MCU_AICE_TMSC"), + MTK_FUNCTION(5, "CONN_WF_MCU_AICE_TMSC"), + MTK_FUNCTION(7, "MBISTREADEN_TRIGGER") + ), + MTK_PIN( + 144, "GPIO144", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO144"), + MTK_FUNCTION(1, "SDA9"), + MTK_FUNCTION(2, "GPS_L5_ELNA_EN"), + MTK_FUNCTION(3, "HFRP_URXD1"), + MTK_FUNCTION(4, "CONN_BGF_MCU_AICE_TCKC"), + MTK_FUNCTION(5, "CONN_WF_MCU_AICE_TCKC"), + MTK_FUNCTION(7, "MBISTWRITEEN_TRIGGER") + ), + MTK_PIN( + 145, "GPIO145", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO145"), + MTK_FUNCTION(1, "SCL10"), + MTK_FUNCTION(2, "SCP_SCL0"), + MTK_FUNCTION(5, "TP_GPIO8_AO") + ), + MTK_PIN( + 146, "GPIO146", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO146"), + MTK_FUNCTION(1, "SDA10"), + MTK_FUNCTION(2, "SCP_SDA0"), + MTK_FUNCTION(5, "TP_GPIO9_AO") + ), + MTK_PIN( + 147, "GPIO147", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO147"), + MTK_FUNCTION(1, "SCL11"), + MTK_FUNCTION(2, "SCP_SCL1"), + MTK_FUNCTION(3, "SCP_DMIC_CLK"), + MTK_FUNCTION(4, "DMIC_CLK"), + MTK_FUNCTION(5, "TP_GPIO10_AO"), + MTK_FUNCTION(6, "EXTIF0_PRI") + ), + MTK_PIN( + 148, "GPIO148", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO148"), + MTK_FUNCTION(1, "SDA11"), + MTK_FUNCTION(2, "SCP_SDA1"), + MTK_FUNCTION(3, "SCP_DMIC_DAT"), + MTK_FUNCTION(4, "DMIC_DAT"), + MTK_FUNCTION(5, "TP_GPIO11_AO"), + MTK_FUNCTION(6, "EXTIF0_GNT_B") + ), + MTK_PIN( + 149, "GPIO149", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO149"), + MTK_FUNCTION(1, "KPROW2"), + MTK_FUNCTION(2, "PWM_VLP"), + MTK_FUNCTION(4, "MD_INT0"), + MTK_FUNCTION(5, "TP_GPIO12_AO"), + MTK_FUNCTION(6, "SCL0"), + MTK_FUNCTION(7, "DBG_MON_A28") + ), + MTK_PIN( + 150, "GPIO150", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO150"), + MTK_FUNCTION(1, "KPCOL2"), + MTK_FUNCTION(2, "PWM_VLP"), + MTK_FUNCTION(3, "CMMCLK5"), + MTK_FUNCTION(4, "MD_INT3"), + MTK_FUNCTION(5, "TP_GPIO13_AO"), + MTK_FUNCTION(6, "SDA0") + ), + MTK_PIN( + 151, "GPIO151", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO151"), + MTK_FUNCTION(1, "SRCLKENAI0"), + MTK_FUNCTION(4, "MD_INT4"), + MTK_FUNCTION(5, "TP_GPIO14_AO"), + MTK_FUNCTION(7, "DBG_MON_A29") + ), + MTK_PIN( + 152, "GPIO152", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO152"), + MTK_FUNCTION(1, "SRCLKENAI1"), + MTK_FUNCTION(4, "SPMI_M_TRIG_FLAG"), + MTK_FUNCTION(5, "TP_GPIO15_AO"), + MTK_FUNCTION(7, "DBG_MON_A30") + ), + MTK_PIN( + 153, "GPIO153", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO153"), + MTK_FUNCTION(1, "MD1_SIM2_SCLK"), + MTK_FUNCTION(2, "DISP_PWM1"), + MTK_FUNCTION(4, "SPMI_P_TRIG_FLAG"), + MTK_FUNCTION(7, "DBG_MON_A0") + ), + MTK_PIN( + 154, "GPIO154", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO154"), + MTK_FUNCTION(1, "MD1_SIM2_SRST"), + MTK_FUNCTION(2, "LCM_RST1"), + MTK_FUNCTION(3, "GPS_L1_ELNA_EN"), + MTK_FUNCTION(4, "CMFLASH2"), + MTK_FUNCTION(5, "MBISTREADEN_TRIGGER"), + MTK_FUNCTION(7, "DBG_MON_A1") + ), + MTK_PIN( + 155, "GPIO155", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO155"), + MTK_FUNCTION(1, "MD1_SIM2_SIO"), + MTK_FUNCTION(2, "DSI_TE1"), + MTK_FUNCTION(3, "GPS_L5_ELNA_EN"), + MTK_FUNCTION(4, "CMFLASH3"), + MTK_FUNCTION(5, "MBISTWRITEEN_TRIGGER"), + MTK_FUNCTION(7, "DBG_MON_A2") + ), + MTK_PIN( + 156, "GPIO156", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO156"), + MTK_FUNCTION(1, "SPMI_M_SCL") + ), + MTK_PIN( + 157, "GPIO157", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO157"), + MTK_FUNCTION(1, "SPMI_M_SDA") + ), + MTK_PIN( + 158, "GPIO158", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO158"), + MTK_FUNCTION(1, "SPMI_P_SCL") + ), + MTK_PIN( + 159, "GPIO159", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO159"), + MTK_FUNCTION(1, "SPMI_P_SDA") + ), + MTK_PIN( + 160, "GPIO160", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO160"), + MTK_FUNCTION(1, "SRCLKENA0") + ), + MTK_PIN( + 161, "GPIO161", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO161"), + MTK_FUNCTION(1, "SCP_VREQ_VAO") + ), + MTK_PIN( + 162, "GPIO162", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO162"), + MTK_FUNCTION(1, "RTC32K_CK") + ), + MTK_PIN( + 163, "GPIO163", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO163"), + MTK_FUNCTION(1, "WATCHDOG") + ), + MTK_PIN( + 164, "GPIO164", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO164"), + MTK_FUNCTION(1, "AUD_CLK_MOSI"), + MTK_FUNCTION(3, "AUD_CLK_MOSI") + ), + MTK_PIN( + 165, "GPIO165", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO165"), + MTK_FUNCTION(1, "AUD_SYNC_MOSI") + ), + MTK_PIN( + 166, "GPIO166", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO166"), + MTK_FUNCTION(1, "AUD_DAT_MOSI0"), + MTK_FUNCTION(3, "AUD_DAT_MOSI0") + ), + MTK_PIN( + 167, "GPIO167", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO167"), + MTK_FUNCTION(1, "AUD_DAT_MOSI1"), + MTK_FUNCTION(3, "AUD_DAT_MOSI1") + ), + MTK_PIN( + 168, "GPIO168", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO168"), + MTK_FUNCTION(1, "AUD_NLE_MOSI0"), + MTK_FUNCTION(2, "AUD_SYNC_MISO") + ), + MTK_PIN( + 169, "GPIO169", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO169"), + MTK_FUNCTION(1, "AUD_NLE_MOSI1"), + MTK_FUNCTION(2, "AUD_CLK_MISO"), + MTK_FUNCTION(3, "AUD_CLK_MISO") + ), + MTK_PIN( + 170, "GPIO170", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO170"), + MTK_FUNCTION(1, "AUD_DAT_MISO0"), + MTK_FUNCTION(2, "VOW_DAT_MISO"), + MTK_FUNCTION(3, "AUD_DAT_MISO0") + ), + MTK_PIN( + 171, "GPIO171", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO171"), + MTK_FUNCTION(1, "AUD_DAT_MISO1"), + MTK_FUNCTION(2, "VOW_CLK_MISO"), + MTK_FUNCTION(3, "AUD_DAT_MISO1") + ), + MTK_PIN( + 172, "GPIO172", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO172"), + MTK_FUNCTION(1, "CONN_TOP_CLK"), + MTK_FUNCTION(7, "DBG_MON_A31") + ), + MTK_PIN( + 173, "GPIO173", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO173"), + MTK_FUNCTION(1, "CONN_TOP_DATA") + ), + MTK_PIN( + 174, "GPIO174", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO174"), + MTK_FUNCTION(1, "CONN_BT_CLK") + ), + MTK_PIN( + 175, "GPIO175", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO175"), + MTK_FUNCTION(1, "CONN_BT_DATA") + ), + MTK_PIN( + 176, "GPIO176", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO176"), + MTK_FUNCTION(1, "CONN_HRST_B") + ), + MTK_PIN( + 177, "GPIO177", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO177"), + MTK_FUNCTION(1, "CONN_WB_PTA") + ), + MTK_PIN( + 178, "GPIO178", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO178"), + MTK_FUNCTION(1, "CONN_WF_CTRL0") + ), + MTK_PIN( + 179, "GPIO179", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO179"), + MTK_FUNCTION(1, "CONN_WF_CTRL1") + ), + MTK_PIN( + 180, "GPIO180", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO180"), + MTK_FUNCTION(1, "CONN_WF_CTRL2") + ), + MTK_PIN( + 181, "GPIO181", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO181"), + MTK_FUNCTION(1, "CONN_WF_CTRL3"), + MTK_FUNCTION(2, "CONN_TOP_CLK_2"), + MTK_FUNCTION(3, "GPS_L1_ELNA_EN") + ), + MTK_PIN( + 182, "GPIO182", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO182"), + MTK_FUNCTION(1, "CONN_WF_CTRL4"), + MTK_FUNCTION(2, "CONN_TOP_DATA_2"), + MTK_FUNCTION(3, "GPS_L5_ELNA_EN") + ), + MTK_PIN( + 183, "GPIO183", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO183"), + MTK_FUNCTION(1, "CONN_HRST_B_2") + ), + MTK_PIN( + 184, "GPIO184", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO184"), + MTK_FUNCTION(1, "MSDC0_DSL"), + MTK_FUNCTION(3, "ANT_SEL13") + ), + MTK_PIN( + 185, "GPIO185", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO185"), + MTK_FUNCTION(1, "MSDC0_CLK"), + MTK_FUNCTION(2, "CONN_TCXOENA_REQ"), + MTK_FUNCTION(3, "ANT_SEL14") + ), + MTK_PIN( + 186, "GPIO186", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO186"), + MTK_FUNCTION(1, "MSDC0_CMD"), + MTK_FUNCTION(2, "GPS_L1_ELNA_EN"), + MTK_FUNCTION(3, "ANT_SEL15"), + MTK_FUNCTION(5, "I2SOUT4_DATA0") + ), + MTK_PIN( + 187, "GPIO187", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO187"), + MTK_FUNCTION(1, "MSDC0_RSTB"), + MTK_FUNCTION(2, "GPS_L5_ELNA_EN"), + MTK_FUNCTION(3, "ANT_SEL16"), + MTK_FUNCTION(5, "I2SOUT4_DATA1") + ), + MTK_PIN( + 188, "GPIO188", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO188"), + MTK_FUNCTION(1, "MSDC0_DAT0"), + MTK_FUNCTION(3, "ANT_SEL17"), + MTK_FUNCTION(5, "I2SOUT4_DATA2") + ), + MTK_PIN( + 189, "GPIO189", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO189"), + MTK_FUNCTION(1, "MSDC0_DAT1"), + MTK_FUNCTION(3, "ANT_SEL18"), + MTK_FUNCTION(5, "I2SOUT4_DATA3") + ), + MTK_PIN( + 190, "GPIO190", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO190"), + MTK_FUNCTION(1, "MSDC0_DAT2"), + MTK_FUNCTION(2, "DMIC1_CLK"), + MTK_FUNCTION(3, "ANT_SEL19"), + MTK_FUNCTION(5, "I2SIN4_BCK") + ), + MTK_PIN( + 191, "GPIO191", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO191"), + MTK_FUNCTION(1, "MSDC0_DAT3"), + MTK_FUNCTION(2, "DMIC1_DAT"), + MTK_FUNCTION(3, "ANT_SEL20"), + MTK_FUNCTION(5, "I2SIN4_DATA0") + ), + MTK_PIN( + 192, "GPIO192", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO192"), + MTK_FUNCTION(1, "MSDC0_DAT4"), + MTK_FUNCTION(2, "IDDIG"), + MTK_FUNCTION(3, "ANT_SEL21"), + MTK_FUNCTION(4, "UFS_MPHY_SCL"), + MTK_FUNCTION(5, "I2SIN4_DATA1") + ), + MTK_PIN( + 193, "GPIO193", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO193"), + MTK_FUNCTION(1, "MSDC0_DAT5"), + MTK_FUNCTION(2, "USB_DRVVBUS"), + MTK_FUNCTION(4, "UFS_MPHY_SDA"), + MTK_FUNCTION(5, "I2SIN4_DATA2") + ), + MTK_PIN( + 194, "GPIO194", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO194"), + MTK_FUNCTION(1, "MSDC0_DAT6"), + MTK_FUNCTION(2, "VBUSVALID"), + MTK_FUNCTION(5, "I2SIN4_DATA3") + ), + MTK_PIN( + 195, "GPIO195", + MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO195"), + MTK_FUNCTION(1, "MSDC0_DAT7"), + MTK_FUNCTION(5, "I2SIN4_LRCK") + ), + MTK_PIN( + 196, "GPIO196", + MTK_EINT_FUNCTION(0, 196), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 197, "GPIO197", + MTK_EINT_FUNCTION(0, 197), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 198, "GPIO198", + MTK_EINT_FUNCTION(0, 198), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 199, "GPIO199", + MTK_EINT_FUNCTION(0, 199), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 200, "GPIO200", + MTK_EINT_FUNCTION(0, 200), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 201, "GPIO201", + MTK_EINT_FUNCTION(0, 201), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 202, "GPIO202", + MTK_EINT_FUNCTION(0, 202), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 203, "GPIO203", + MTK_EINT_FUNCTION(0, 203), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 204, "GPIO204", + MTK_EINT_FUNCTION(0, 204), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 205, "GPIO205", + MTK_EINT_FUNCTION(0, 205), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 206, "GPIO206", + MTK_EINT_FUNCTION(0, 206), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 207, "GPIO207", + MTK_EINT_FUNCTION(0, 207), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 208, "GPIO208", + MTK_EINT_FUNCTION(0, 208), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 209, "GPIO209", + MTK_EINT_FUNCTION(0, 209), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 210, "GPIO210", + MTK_EINT_FUNCTION(0, 210), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 211, "GPIO211", + MTK_EINT_FUNCTION(0, 211), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 212, "GPIO212", + MTK_EINT_FUNCTION(0, 212), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 213, "GPIO213", + MTK_EINT_FUNCTION(0, 213), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 214, "GPIO214", + MTK_EINT_FUNCTION(0, 214), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), + MTK_PIN( + 215, "GPIO215", + MTK_EINT_FUNCTION(0, 215), + DRV_GRP4, + MTK_FUNCTION(0, NULL) + ), +}; + +static struct mtk_eint_pin eint_pins_mt6878[] = { + MTK_EINT_PIN(0, 0, 0, 1), + MTK_EINT_PIN(1, 0, 1, 1), + MTK_EINT_PIN(2, 0, 2, 1), + MTK_EINT_PIN(3, 0, 3, 1), + MTK_EINT_PIN(4, 0, 4, 1), + MTK_EINT_PIN(5, 0, 5, 1), + MTK_EINT_PIN(6, 1, 0, 1), + MTK_EINT_PIN(7, 1, 1, 1), + MTK_EINT_PIN(8, 1, 2, 1), + MTK_EINT_PIN(9, 1, 3, 1), + MTK_EINT_PIN(10, 1, 4, 1), + MTK_EINT_PIN(11, 1, 5, 1), + MTK_EINT_PIN(12, 1, 6, 1), + MTK_EINT_PIN(13, 2, 0, 1), + MTK_EINT_PIN(14, 2, 1, 1), + MTK_EINT_PIN(15, 2, 2, 1), + MTK_EINT_PIN(16, 2, 3, 1), + MTK_EINT_PIN(17, 2, 4, 1), + MTK_EINT_PIN(18, 2, 5, 1), + MTK_EINT_PIN(19, 0, 6, 1), + MTK_EINT_PIN(20, 0, 7, 1), + MTK_EINT_PIN(21, 0, 8, 1), + MTK_EINT_PIN(22, 0, 9, 1), + MTK_EINT_PIN(23, 0, 10, 1), + MTK_EINT_PIN(24, 0, 11, 1), + MTK_EINT_PIN(25, 0, 12, 1), + MTK_EINT_PIN(26, 0, 13, 1), + MTK_EINT_PIN(27, 0, 14, 1), + MTK_EINT_PIN(28, 0, 15, 1), + MTK_EINT_PIN(29, 2, 6, 1), + MTK_EINT_PIN(30, 2, 7, 1), + MTK_EINT_PIN(31, 2, 8, 1), + MTK_EINT_PIN(32, 2, 9, 1), + MTK_EINT_PIN(33, 0, 16, 1), + MTK_EINT_PIN(34, 0, 17, 1), + MTK_EINT_PIN(35, 0, 18, 1), + MTK_EINT_PIN(36, 0, 19, 0), + MTK_EINT_PIN(37, 0, 20, 0), + MTK_EINT_PIN(38, 0, 21, 0), + MTK_EINT_PIN(39, 0, 22, 0), + MTK_EINT_PIN(40, 0, 23, 0), + MTK_EINT_PIN(41, 1, 7, 0), + MTK_EINT_PIN(42, 1, 8, 0), + MTK_EINT_PIN(43, 1, 9, 0), + MTK_EINT_PIN(44, 1, 10, 0), + MTK_EINT_PIN(45, 1, 11, 0), + MTK_EINT_PIN(46, 1, 12, 0), + MTK_EINT_PIN(47, 1, 13, 0), + MTK_EINT_PIN(48, 0, 24, 0), + MTK_EINT_PIN(49, 0, 25, 0), + MTK_EINT_PIN(50, 0, 26, 0), + MTK_EINT_PIN(51, 0, 27, 0), + MTK_EINT_PIN(52, 0, 28, 0), + MTK_EINT_PIN(53, 0, 29, 0), + MTK_EINT_PIN(54, 0, 30, 0), + MTK_EINT_PIN(55, 0, 31, 0), + MTK_EINT_PIN(56, 0, 32, 0), + MTK_EINT_PIN(57, 0, 33, 0), + MTK_EINT_PIN(58, 0, 34, 0), + MTK_EINT_PIN(59, 0, 35, 0), + MTK_EINT_PIN(60, 0, 36, 0), + MTK_EINT_PIN(61, 0, 37, 0), + MTK_EINT_PIN(62, 0, 38, 0), + MTK_EINT_PIN(63, 0, 39, 0), + MTK_EINT_PIN(64, 0, 40, 0), + MTK_EINT_PIN(65, 0, 41, 0), + MTK_EINT_PIN(66, 0, 42, 0), + MTK_EINT_PIN(67, 0, 43, 0), + MTK_EINT_PIN(68, 0, 44, 0), + MTK_EINT_PIN(69, 0, 45, 0), + MTK_EINT_PIN(70, 0, 46, 0), + MTK_EINT_PIN(71, 0, 47, 0), + MTK_EINT_PIN(72, 0, 48, 0), + MTK_EINT_PIN(73, 0, 49, 0), + MTK_EINT_PIN(74, 0, 50, 0), + MTK_EINT_PIN(75, 0, 51, 0), + MTK_EINT_PIN(76, 0, 52, 0), + MTK_EINT_PIN(77, 1, 14, 0), + MTK_EINT_PIN(78, 1, 15, 0), + MTK_EINT_PIN(79, 1, 16, 0), + MTK_EINT_PIN(80, 1, 17, 0), + MTK_EINT_PIN(81, 1, 18, 0), + MTK_EINT_PIN(82, 1, 19, 0), + MTK_EINT_PIN(83, 1, 20, 0), + MTK_EINT_PIN(84, 1, 21, 0), + MTK_EINT_PIN(85, 1, 22, 0), + MTK_EINT_PIN(86, 1, 23, 0), + MTK_EINT_PIN(87, 1, 24, 0), + MTK_EINT_PIN(88, 1, 25, 0), + MTK_EINT_PIN(89, 1, 26, 0), + MTK_EINT_PIN(90, 1, 27, 0), + MTK_EINT_PIN(91, 1, 28, 0), + MTK_EINT_PIN(92, 0, 53, 0), + MTK_EINT_PIN(93, 0, 54, 0), + MTK_EINT_PIN(94, 0, 55, 0), + MTK_EINT_PIN(95, 0, 56, 0), + MTK_EINT_PIN(96, 0, 57, 0), + MTK_EINT_PIN(97, 2, 10, 0), + MTK_EINT_PIN(98, 2, 11, 0), + MTK_EINT_PIN(99, 1, 29, 0), + MTK_EINT_PIN(100, 1, 30, 0), + MTK_EINT_PIN(101, 1, 31, 0), + MTK_EINT_PIN(102, 1, 32, 0), + MTK_EINT_PIN(103, 1, 33, 0), + MTK_EINT_PIN(104, 1, 34, 0), + MTK_EINT_PIN(105, 1, 35, 0), + MTK_EINT_PIN(106, 1, 36, 0), + MTK_EINT_PIN(107, 1, 37, 0), + MTK_EINT_PIN(108, 1, 38, 0), + MTK_EINT_PIN(109, 1, 39, 0), + MTK_EINT_PIN(110, 1, 40, 0), + MTK_EINT_PIN(111, 1, 41, 0), + MTK_EINT_PIN(112, 1, 42, 0), + MTK_EINT_PIN(113, 1, 43, 0), + MTK_EINT_PIN(114, 1, 44, 0), + MTK_EINT_PIN(115, 1, 45, 0), + MTK_EINT_PIN(116, 1, 46, 0), + MTK_EINT_PIN(196, 3, 0, 0), + MTK_EINT_PIN(197, 3, 1, 0), + MTK_EINT_PIN(198, 3, 2, 0), + MTK_EINT_PIN(199, 3, 3, 0), + MTK_EINT_PIN(200, 3, 4, 0), + MTK_EINT_PIN(201, 3, 5, 0), + MTK_EINT_PIN(202, 3, 6, 0), + MTK_EINT_PIN(203, 3, 7, 0), + MTK_EINT_PIN(204, 3, 8, 0), + MTK_EINT_PIN(205, 3, 9, 0), + MTK_EINT_PIN(206, 3, 10, 0), + MTK_EINT_PIN(207, 3, 11, 0), + MTK_EINT_PIN(208, 3, 12, 0), + MTK_EINT_PIN(209, 3, 13, 0), + MTK_EINT_PIN(210, 3, 14, 0), + MTK_EINT_PIN(211, 3, 15, 0), + MTK_EINT_PIN(212, 3, 16, 0), + MTK_EINT_PIN(213, 3, 17, 0), + MTK_EINT_PIN(214, 3, 18, 0), + MTK_EINT_PIN(215, 3, 19, 0), +}; + +#endif /* __PINCTRL_MTK_MT6878_H */ diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 5de6ff62c69b..366775841c63 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -54,6 +54,8 @@ static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_SLEEP_HARDWARE_STATE, "sleep hardware state", NULL, false), PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL, true), PCONFDUMP(PIN_CONFIG_SKEW_DELAY, "skew delay", NULL, true), + PCONFDUMP(PIN_CONFIG_SKEW_DELAY_INPUT_PS, "input skew delay", "ps", true), + PCONFDUMP(PIN_CONFIG_SKEW_DELAY_OUTPUT_PS, "output skew delay", "ps", true), }; static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, @@ -65,11 +67,12 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, int i; for (i = 0; i < nitems; i++) { + const struct pin_config_item *item = &items[i]; unsigned long config; int ret; /* We want to check out this parameter */ - config = pinconf_to_config_packed(items[i].param, 0); + config = pinconf_to_config_packed(item->param, 0); if (gname) ret = pin_config_group_get(dev_name(pctldev->dev), gname, &config); @@ -86,15 +89,22 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, if (*print_sep) seq_puts(s, ", "); *print_sep = 1; - seq_puts(s, items[i].display); + seq_puts(s, item->display); /* Print unit if available */ - if (items[i].has_arg) { + if (item->has_arg) { u32 val = pinconf_to_config_argument(config); - if (items[i].format) - seq_printf(s, " (%u %s)", val, items[i].format); + if (item->format) + seq_printf(s, " (%u %s)", val, item->format); else seq_printf(s, " (0x%x)", val); + + if (item->values && item->num_values) { + if (val < item->num_values) + seq_printf(s, " \"%s\"", item->values[val]); + else + seq_puts(s, " \"(unknown)\""); + } } } } @@ -104,7 +114,7 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, * @pctldev: Pincontrol device * @s: File to print to * @gname: Group name specifying pins - * @pin: Pin number specyfying pin + * @pin: Pin number specifying pin * * Print the pinconf configuration for the requested pin(s) to @s. Pins can be * specified either by pin using @pin or by group using @gname. Only one needs @@ -190,6 +200,8 @@ static const struct pinconf_generic_params dt_params[] = { { "sleep-hardware-state", PIN_CONFIG_SLEEP_HARDWARE_STATE, 0 }, { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, { "skew-delay", PIN_CONFIG_SKEW_DELAY, 0 }, + { "skew-delay-input-ps", PIN_CONFIG_SKEW_DELAY_INPUT_PS, 0 }, + { "skew-delay-output-ps", PIN_CONFIG_SKEW_DELAY_OUTPUT_PS, 0 }, }; /** @@ -205,10 +217,10 @@ static const struct pinconf_generic_params dt_params[] = { * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg * needs to have enough memory allocated to hold all possible entries. */ -static void parse_dt_cfg(struct device_node *np, - const struct pinconf_generic_params *params, - unsigned int count, unsigned long *cfg, - unsigned int *ncfg) +static int parse_dt_cfg(struct device_node *np, + const struct pinconf_generic_params *params, + unsigned int count, unsigned long *cfg, + unsigned int *ncfg) { int i; @@ -217,7 +229,19 @@ static void parse_dt_cfg(struct device_node *np, int ret; const struct pinconf_generic_params *par = ¶ms[i]; - ret = of_property_read_u32(np, par->property, &val); + if (par->values && par->num_values) { + ret = fwnode_property_match_property_string(of_fwnode_handle(np), + par->property, + par->values, par->num_values); + if (ret == -ENOENT) + return ret; + if (ret >= 0) { + val = ret; + ret = 0; + } + } else { + ret = of_property_read_u32(np, par->property, &val); + } /* property not found */ if (ret == -EINVAL) @@ -231,6 +255,8 @@ static void parse_dt_cfg(struct device_node *np, cfg[*ncfg] = pinconf_to_config_packed(par->param, val); (*ncfg)++; } + + return 0; } /** @@ -242,7 +268,7 @@ static void parse_dt_cfg(struct device_node *np, * @pmux: array with pin mux value entries * @npins: number of pins * - * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits. + * pinmux property: mux value [0,7]bits and pin identity [8,31]bits. */ int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, unsigned int **pid, unsigned int **pmux, @@ -323,13 +349,16 @@ int pinconf_generic_parse_dt_config(struct device_node *np, if (!cfg) return -ENOMEM; - parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg); + ret = parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg); + if (ret) + return ret; if (pctldev && pctldev->desc->num_custom_params && - pctldev->desc->custom_params) - parse_dt_cfg(np, pctldev->desc->custom_params, - pctldev->desc->num_custom_params, cfg, &ncfg); - - ret = 0; + pctldev->desc->custom_params) { + ret = parse_dt_cfg(np, pctldev->desc->custom_params, + pctldev->desc->num_custom_params, cfg, &ncfg); + if (ret) + return ret; + } /* no configs found at all */ if (ncfg == 0) { diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index a17fcaddf490..586f2f67c617 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -44,17 +44,6 @@ #define MCP_GPIO 0x09 #define MCP_OLAT 0x0a -static const struct reg_default mcp23x08_defaults[] = { - {.reg = MCP_IODIR, .def = 0xff}, - {.reg = MCP_IPOL, .def = 0x00}, - {.reg = MCP_GPINTEN, .def = 0x00}, - {.reg = MCP_DEFVAL, .def = 0x00}, - {.reg = MCP_INTCON, .def = 0x00}, - {.reg = MCP_IOCON, .def = 0x00}, - {.reg = MCP_GPPU, .def = 0x00}, - {.reg = MCP_OLAT, .def = 0x00}, -}; - static const struct regmap_range mcp23x08_volatile_range = { .range_min = MCP_INTF, .range_max = MCP_GPIO, @@ -82,25 +71,13 @@ const struct regmap_config mcp23x08_regmap = { .reg_stride = 1, .volatile_table = &mcp23x08_volatile_table, .precious_table = &mcp23x08_precious_table, - .reg_defaults = mcp23x08_defaults, - .num_reg_defaults = ARRAY_SIZE(mcp23x08_defaults), - .cache_type = REGCACHE_FLAT, + .num_reg_defaults_raw = MCP_OLAT + 1, + .cache_type = REGCACHE_MAPLE, .max_register = MCP_OLAT, .disable_locking = true, /* mcp->lock protects the regmap */ }; EXPORT_SYMBOL_GPL(mcp23x08_regmap); -static const struct reg_default mcp23x17_defaults[] = { - {.reg = MCP_IODIR << 1, .def = 0xffff}, - {.reg = MCP_IPOL << 1, .def = 0x0000}, - {.reg = MCP_GPINTEN << 1, .def = 0x0000}, - {.reg = MCP_DEFVAL << 1, .def = 0x0000}, - {.reg = MCP_INTCON << 1, .def = 0x0000}, - {.reg = MCP_IOCON << 1, .def = 0x0000}, - {.reg = MCP_GPPU << 1, .def = 0x0000}, - {.reg = MCP_OLAT << 1, .def = 0x0000}, -}; - static const struct regmap_range mcp23x17_volatile_range = { .range_min = MCP_INTF << 1, .range_max = MCP_GPIO << 1, @@ -129,9 +106,8 @@ const struct regmap_config mcp23x17_regmap = { .max_register = MCP_OLAT << 1, .volatile_table = &mcp23x17_volatile_table, .precious_table = &mcp23x17_precious_table, - .reg_defaults = mcp23x17_defaults, - .num_reg_defaults = ARRAY_SIZE(mcp23x17_defaults), - .cache_type = REGCACHE_FLAT, + .num_reg_defaults_raw = MCP_OLAT + 1, + .cache_type = REGCACHE_MAPLE, .val_format_endian = REGMAP_ENDIAN_LITTLE, .disable_locking = true, /* mcp->lock protects the regmap */ }; @@ -642,14 +618,6 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, mcp->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - /* - * Reset the chip - we don't really know what state it's in, so reset - * all pins to input first to prevent surprises. - */ - ret = mcp_write(mcp, MCP_IODIR, mcp->chip.ngpio == 16 ? 0xFFFF : 0xFF); - if (ret < 0) - return ret; - /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, * and MCP_IOCON.HAEN = 1, so we work with all chips. */ diff --git a/drivers/pinctrl/pinctrl-mpfs-iomux0.c b/drivers/pinctrl/pinctrl-mpfs-iomux0.c new file mode 100644 index 000000000000..cf5b2e4e8f5b --- /dev/null +++ b/drivers/pinctrl/pinctrl-mpfs-iomux0.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/module.h> +#include <linux/mfd/syscon.h> +#include <linux/mod_devicetable.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/seq_file.h> + +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include "core.h" +#include "pinctrl-utils.h" +#include "pinconf.h" +#include "pinmux.h" + +#define MPFS_IOMUX0_REG 0x200 + +struct mpfs_iomux0_pinctrl { + struct pinctrl_dev *pctrl; + struct device *dev; + struct regmap *regmap; + struct pinctrl_desc desc; +}; + +struct mpfs_iomux0_pin_group { + const char *name; + const unsigned int *pins; + u32 mask; + u32 setting; +}; + +struct mpfs_iomux0_function { + const char *name; + const char * const *groups; +}; + +static const struct pinctrl_pin_desc mpfs_iomux0_pins[] = { + PINCTRL_PIN(0, "spi0"), + PINCTRL_PIN(1, "spi1"), + PINCTRL_PIN(2, "i2c0"), + PINCTRL_PIN(3, "i2c1"), + PINCTRL_PIN(4, "can0"), + PINCTRL_PIN(5, "can1"), + PINCTRL_PIN(6, "qspi"), + PINCTRL_PIN(7, "uart0"), + PINCTRL_PIN(8, "uart1"), + PINCTRL_PIN(9, "uart2"), + PINCTRL_PIN(10, "uart3"), + PINCTRL_PIN(11, "uart4"), + PINCTRL_PIN(12, "mdio0"), + PINCTRL_PIN(13, "mdio1"), +}; + +static const unsigned int mpfs_iomux0_spi0_pins[] = { 0 }; +static const unsigned int mpfs_iomux0_spi1_pins[] = { 1 }; +static const unsigned int mpfs_iomux0_i2c0_pins[] = { 2 }; +static const unsigned int mpfs_iomux0_i2c1_pins[] = { 3 }; +static const unsigned int mpfs_iomux0_can0_pins[] = { 4 }; +static const unsigned int mpfs_iomux0_can1_pins[] = { 5 }; +static const unsigned int mpfs_iomux0_qspi_pins[] = { 6 }; +static const unsigned int mpfs_iomux0_uart0_pins[] = { 7 }; +static const unsigned int mpfs_iomux0_uart1_pins[] = { 8 }; +static const unsigned int mpfs_iomux0_uart2_pins[] = { 9 }; +static const unsigned int mpfs_iomux0_uart3_pins[] = { 10 }; +static const unsigned int mpfs_iomux0_uart4_pins[] = { 11 }; +static const unsigned int mpfs_iomux0_mdio0_pins[] = { 12 }; +static const unsigned int mpfs_iomux0_mdio1_pins[] = { 13 }; + +#define MPFS_IOMUX0_GROUP(_name, _mask) { \ + .name = #_name "_mssio", \ + .pins = mpfs_iomux0_##_name##_pins, \ + .mask = _mask, \ + .setting = 0x0, \ +}, { \ + .name = #_name "_fabric", \ + .pins = mpfs_iomux0_##_name##_pins, \ + .mask = _mask, \ + .setting = _mask, \ +} + +static const struct mpfs_iomux0_pin_group mpfs_iomux0_pin_groups[] = { + MPFS_IOMUX0_GROUP(spi0, BIT(0)), + MPFS_IOMUX0_GROUP(spi1, BIT(1)), + MPFS_IOMUX0_GROUP(i2c0, BIT(2)), + MPFS_IOMUX0_GROUP(i2c1, BIT(3)), + MPFS_IOMUX0_GROUP(can0, BIT(4)), + MPFS_IOMUX0_GROUP(can1, BIT(5)), + MPFS_IOMUX0_GROUP(qspi, BIT(6)), + MPFS_IOMUX0_GROUP(uart0, BIT(7)), + MPFS_IOMUX0_GROUP(uart1, BIT(8)), + MPFS_IOMUX0_GROUP(uart2, BIT(9)), + MPFS_IOMUX0_GROUP(uart3, BIT(10)), + MPFS_IOMUX0_GROUP(uart4, BIT(11)), + MPFS_IOMUX0_GROUP(mdio0, BIT(12)), + MPFS_IOMUX0_GROUP(mdio1, BIT(13)), +}; + +static const char * const mpfs_iomux0_spi0_groups[] = { "spi0_mssio", "spi0_fabric" }; +static const char * const mpfs_iomux0_spi1_groups[] = { "spi1_mssio", "spi1_fabric" }; +static const char * const mpfs_iomux0_i2c0_groups[] = { "i2c0_mssio", "i2c0_fabric" }; +static const char * const mpfs_iomux0_i2c1_groups[] = { "i2c1_mssio", "i2c1_fabric" }; +static const char * const mpfs_iomux0_can0_groups[] = { "can0_mssio", "can0_fabric" }; +static const char * const mpfs_iomux0_can1_groups[] = { "can1_mssio", "can1_fabric" }; +static const char * const mpfs_iomux0_qspi_groups[] = { "qspi_mssio", "qspi_fabric" }; +static const char * const mpfs_iomux0_uart0_groups[] = { "uart0_mssio", "uart0_fabric" }; +static const char * const mpfs_iomux0_uart1_groups[] = { "uart1_mssio", "uart1_fabric" }; +static const char * const mpfs_iomux0_uart2_groups[] = { "uart2_mssio", "uart2_fabric" }; +static const char * const mpfs_iomux0_uart3_groups[] = { "uart3_mssio", "uart3_fabric" }; +static const char * const mpfs_iomux0_uart4_groups[] = { "uart4_mssio", "uart4_fabric" }; +static const char * const mpfs_iomux0_mdio0_groups[] = { "mdio0_mssio", "mdio0_fabric" }; +static const char * const mpfs_iomux0_mdio1_groups[] = { "mdio1_mssio", "mdio1_fabric" }; + +#define MPFS_IOMUX0_FUNCTION(_name) { \ + .name = #_name, \ + .groups = mpfs_iomux0_##_name##_groups, \ +} + +static const struct mpfs_iomux0_function mpfs_iomux0_functions[] = { + MPFS_IOMUX0_FUNCTION(spi0), + MPFS_IOMUX0_FUNCTION(spi1), + MPFS_IOMUX0_FUNCTION(i2c0), + MPFS_IOMUX0_FUNCTION(i2c1), + MPFS_IOMUX0_FUNCTION(can0), + MPFS_IOMUX0_FUNCTION(can1), + MPFS_IOMUX0_FUNCTION(qspi), + MPFS_IOMUX0_FUNCTION(uart0), + MPFS_IOMUX0_FUNCTION(uart1), + MPFS_IOMUX0_FUNCTION(uart2), + MPFS_IOMUX0_FUNCTION(uart3), + MPFS_IOMUX0_FUNCTION(uart4), + MPFS_IOMUX0_FUNCTION(mdio0), + MPFS_IOMUX0_FUNCTION(mdio1), +}; + +static void mpfs_iomux0_pin_dbg_show(struct pinctrl_dev *pctrl_dev, struct seq_file *seq, + unsigned int pin) +{ + struct mpfs_iomux0_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); + u32 val; + + seq_printf(seq, "reg: %x, pin: %u ", MPFS_IOMUX0_REG, pin); + + regmap_read(pctrl->regmap, MPFS_IOMUX0_REG, &val); + val = (val & BIT(pin)) >> pin; + + seq_printf(seq, "val: %x\n", val); +} + +static int mpfs_iomux0_groups_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(mpfs_iomux0_pin_groups); +} + +static const char *mpfs_iomux0_group_name(struct pinctrl_dev *pctldev, unsigned int selector) +{ + return mpfs_iomux0_pin_groups[selector].name; +} + +static int mpfs_iomux0_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, + const unsigned int **pins, unsigned int *num_pins) +{ + *pins = mpfs_iomux0_pin_groups[selector].pins; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops mpfs_iomux0_pinctrl_ops = { + .get_groups_count = mpfs_iomux0_groups_count, + .get_group_name = mpfs_iomux0_group_name, + .get_group_pins = mpfs_iomux0_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_free_map, + .pin_dbg_show = mpfs_iomux0_pin_dbg_show, +}; + +static int mpfs_iomux0_pinmux_set_mux(struct pinctrl_dev *pctrl_dev, unsigned int fsel, + unsigned int gsel) +{ + struct mpfs_iomux0_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); + struct device *dev = pctrl->dev; + const struct mpfs_iomux0_pin_group *group; + const struct mpfs_iomux0_function *function; + + group = &mpfs_iomux0_pin_groups[gsel]; + function = &mpfs_iomux0_functions[fsel]; + + dev_dbg(dev, "Setting func %s mask %x setting %x\n", + function->name, group->mask, group->setting); + regmap_assign_bits(pctrl->regmap, MPFS_IOMUX0_REG, group->mask, group->setting); + + return 0; +} + +static int mpfs_iomux0_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(mpfs_iomux0_functions); +} + +static const char *mpfs_iomux0_pinmux_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return mpfs_iomux0_functions[selector].name; +} + +static int mpfs_iomux0_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + *groups = mpfs_iomux0_functions[selector].groups; + *num_groups = 2; + + return 0; +} + +static const struct pinmux_ops mpfs_iomux0_pinmux_ops = { + .get_functions_count = mpfs_iomux0_pinmux_get_funcs_count, + .get_function_name = mpfs_iomux0_pinmux_get_func_name, + .get_function_groups = mpfs_iomux0_pinmux_get_groups, + .set_mux = mpfs_iomux0_pinmux_set_mux, +}; + +static int mpfs_iomux0_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mpfs_iomux0_pinctrl *pctrl; + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->regmap = device_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(pctrl->regmap)) + dev_err_probe(dev, PTR_ERR(pctrl->regmap), "Failed to find syscon regmap\n"); + + pctrl->desc.name = dev_name(dev); + pctrl->desc.pins = mpfs_iomux0_pins; + pctrl->desc.npins = ARRAY_SIZE(mpfs_iomux0_pins); + pctrl->desc.pctlops = &mpfs_iomux0_pinctrl_ops; + pctrl->desc.pmxops = &mpfs_iomux0_pinmux_ops; + pctrl->desc.owner = THIS_MODULE; + + pctrl->dev = dev; + + platform_set_drvdata(pdev, pctrl); + + pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl); + if (IS_ERR(pctrl->pctrl)) + return PTR_ERR(pctrl->pctrl); + + return 0; +} + +static const struct of_device_id mpfs_iomux0_of_match[] = { + { .compatible = "microchip,mpfs-pinctrl-iomux0" }, + { } +}; +MODULE_DEVICE_TABLE(of, mpfs_iomux0_of_match); + +static struct platform_driver mpfs_iomux0_driver = { + .driver = { + .name = "mpfs-pinctrl-iomux0", + .of_match_table = mpfs_iomux0_of_match, + }, + .probe = mpfs_iomux0_probe, +}; +module_platform_driver(mpfs_iomux0_driver); + +MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>"); +MODULE_DESCRIPTION("Polarfire SoC iomux0 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-pic64gx-gpio2.c b/drivers/pinctrl/pinctrl-pic64gx-gpio2.c new file mode 100644 index 000000000000..f322bb5e6181 --- /dev/null +++ b/drivers/pinctrl/pinctrl-pic64gx-gpio2.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/bitfield.h> +#include <linux/module.h> +#include <linux/mfd/syscon.h> +#include <linux/mod_devicetable.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/seq_file.h> + +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include "pinctrl-utils.h" + +#define PIC64GX_PINMUX_REG 0x0 + +static const struct regmap_config pic64gx_gpio2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .val_format_endian = REGMAP_ENDIAN_LITTLE, + .max_register = 0x0, +}; + +struct pic64gx_gpio2_pinctrl { + struct pinctrl_dev *pctrl; + struct device *dev; + struct regmap *regmap; + struct pinctrl_desc desc; +}; + +struct pic64gx_gpio2_pin_group { + const char *name; + const unsigned int *pins; + const unsigned int num_pins; + u32 mask; + u32 setting; +}; + +struct pic64gx_gpio2_function { + const char *name; + const char * const *groups; + const unsigned int num_groups; +}; + +static const struct pinctrl_pin_desc pic64gx_gpio2_pins[] = { + PINCTRL_PIN(0, "E14"), + PINCTRL_PIN(1, "E15"), + PINCTRL_PIN(2, "F16"), + PINCTRL_PIN(3, "F17"), + PINCTRL_PIN(4, "D19"), + PINCTRL_PIN(5, "B18"), + PINCTRL_PIN(6, "B10"), + PINCTRL_PIN(7, "C14"), + PINCTRL_PIN(8, "E18"), + PINCTRL_PIN(9, "D18"), + PINCTRL_PIN(10, "E19"), + PINCTRL_PIN(11, "C7"), + PINCTRL_PIN(12, "D6"), + PINCTRL_PIN(13, "D7"), + PINCTRL_PIN(14, "C9"), + PINCTRL_PIN(15, "C10"), + PINCTRL_PIN(16, "A5"), + PINCTRL_PIN(17, "A6"), + PINCTRL_PIN(18, "D8"), + PINCTRL_PIN(19, "D9"), + PINCTRL_PIN(20, "B8"), + PINCTRL_PIN(21, "A8"), + PINCTRL_PIN(22, "C12"), + PINCTRL_PIN(23, "B12"), + PINCTRL_PIN(24, "A11"), + PINCTRL_PIN(25, "A10"), + PINCTRL_PIN(26, "D11"), + PINCTRL_PIN(27, "C11"), + PINCTRL_PIN(28, "B9"), +}; + +static const unsigned int pic64gx_gpio2_mdio0_pins[] = { + 0, 1 +}; + +static const unsigned int pic64gx_gpio2_mdio1_pins[] = { + 2, 3 +}; + +static const unsigned int pic64gx_gpio2_spi0_pins[] = { + 4, 5, 10, 11 +}; + +static const unsigned int pic64gx_gpio2_can0_pins[] = { + 6, 24, 28 +}; + +static const unsigned int pic64gx_gpio2_pcie_pins[] = { + 7, 8, 9 +}; + +static const unsigned int pic64gx_gpio2_qspi_pins[] = { + 12, 13, 14, 15, 16, 17 +}; + +static const unsigned int pic64gx_gpio2_uart3_pins[] = { + 18, 19 +}; + +static const unsigned int pic64gx_gpio2_uart4_pins[] = { + 20, 21 +}; + +static const unsigned int pic64gx_gpio2_can1_pins[] = { + 22, 23, 25 +}; + +static const unsigned int pic64gx_gpio2_uart2_pins[] = { + 26, 27 +}; + +#define PIC64GX_PINCTRL_GROUP(_name, _mask) { \ + .name = "gpio_" #_name, \ + .pins = pic64gx_gpio2_##_name##_pins, \ + .num_pins = ARRAY_SIZE(pic64gx_gpio2_##_name##_pins), \ + .mask = _mask, \ + .setting = 0x0, \ +}, { \ + .name = #_name, \ + .pins = pic64gx_gpio2_##_name##_pins, \ + .num_pins = ARRAY_SIZE(pic64gx_gpio2_##_name##_pins), \ + .mask = _mask, \ + .setting = _mask, \ +} + +static const struct pic64gx_gpio2_pin_group pic64gx_gpio2_pin_groups[] = { + PIC64GX_PINCTRL_GROUP(mdio0, BIT(0) | BIT(1)), + PIC64GX_PINCTRL_GROUP(mdio1, BIT(2) | BIT(3)), + PIC64GX_PINCTRL_GROUP(spi0, BIT(4) | BIT(5) | BIT(10) | BIT(11)), + PIC64GX_PINCTRL_GROUP(can0, BIT(6) | BIT(24) | BIT(28)), + PIC64GX_PINCTRL_GROUP(pcie, BIT(7) | BIT(8) | BIT(9)), + PIC64GX_PINCTRL_GROUP(qspi, GENMASK(17, 12)), + PIC64GX_PINCTRL_GROUP(uart3, BIT(18) | BIT(19)), + PIC64GX_PINCTRL_GROUP(uart4, BIT(20) | BIT(21)), + PIC64GX_PINCTRL_GROUP(can1, BIT(22) | BIT(23) | BIT(25)), + PIC64GX_PINCTRL_GROUP(uart2, BIT(26) | BIT(27)), +}; + +static const char * const pic64gx_gpio2_gpio_groups[] = { + "gpio_mdio0", "gpio_mdio1", "gpio_spi0", "gpio_can0", "gpio_pcie", + "gpio_qspi", "gpio_uart3", "gpio_uart4", "gpio_can1", "gpio_uart2" +}; + +static const char * const pic64gx_gpio2_mdio0_groups[] = { + "mdio0" +}; + +static const char * const pic64gx_gpio2_mdio1_groups[] = { + "mdio1" +}; + +static const char * const pic64gx_gpio2_spi0_groups[] = { + "spi0" +}; + +static const char * const pic64gx_gpio2_can0_groups[] = { + "can0" +}; + +static const char * const pic64gx_gpio2_pcie_groups[] = { + "pcie" +}; + +static const char * const pic64gx_gpio2_qspi_groups[] = { + "qspi" +}; + +static const char * const pic64gx_gpio2_uart3_groups[] = { + "uart3" +}; + +static const char * const pic64gx_gpio2_uart4_groups[] = { + "uart4" +}; + +static const char * const pic64gx_gpio2_can1_groups[] = { + "can1" +}; + +static const char * const pic64gx_gpio2_uart2_groups[] = { + "uart2" +}; + +#define PIC64GX_PINCTRL_FUNCTION(_name) { \ + .name = #_name, \ + .groups = pic64gx_gpio2_##_name##_groups, \ + .num_groups = ARRAY_SIZE(pic64gx_gpio2_##_name##_groups), \ +} + +static const struct pic64gx_gpio2_function pic64gx_gpio2_functions[] = { + PIC64GX_PINCTRL_FUNCTION(gpio), + PIC64GX_PINCTRL_FUNCTION(mdio0), + PIC64GX_PINCTRL_FUNCTION(mdio1), + PIC64GX_PINCTRL_FUNCTION(spi0), + PIC64GX_PINCTRL_FUNCTION(can0), + PIC64GX_PINCTRL_FUNCTION(pcie), + PIC64GX_PINCTRL_FUNCTION(qspi), + PIC64GX_PINCTRL_FUNCTION(uart3), + PIC64GX_PINCTRL_FUNCTION(uart4), + PIC64GX_PINCTRL_FUNCTION(can1), + PIC64GX_PINCTRL_FUNCTION(uart2), +}; + +static void pic64gx_gpio2_pin_dbg_show(struct pinctrl_dev *pctrl_dev, struct seq_file *seq, + unsigned int pin) +{ + struct pic64gx_gpio2_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); + u32 val; + + regmap_read(pctrl->regmap, PIC64GX_PINMUX_REG, &val); + val = (val & BIT(pin)) >> pin; + seq_printf(seq, "pin: %u val: %x\n", pin, val); +} + +static int pic64gx_gpio2_groups_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pic64gx_gpio2_pin_groups); +} + +static const char *pic64gx_gpio2_group_name(struct pinctrl_dev *pctldev, unsigned int selector) +{ + return pic64gx_gpio2_pin_groups[selector].name; +} + +static int pic64gx_gpio2_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, + const unsigned int **pins, unsigned int *num_pins) +{ + *pins = pic64gx_gpio2_pin_groups[selector].pins; + *num_pins = pic64gx_gpio2_pin_groups[selector].num_pins; + + return 0; +} + +static const struct pinctrl_ops pic64gx_gpio2_pinctrl_ops = { + .get_groups_count = pic64gx_gpio2_groups_count, + .get_group_name = pic64gx_gpio2_group_name, + .get_group_pins = pic64gx_gpio2_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_free_map, + .pin_dbg_show = pic64gx_gpio2_pin_dbg_show, +}; + +static int pic64gx_gpio2_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pic64gx_gpio2_functions); +} + +static const char *pic64gx_gpio2_pinmux_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return pic64gx_gpio2_functions[selector].name; +} + +static int pic64gx_gpio2_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + *groups = pic64gx_gpio2_functions[selector].groups; + *num_groups = pic64gx_gpio2_functions[selector].num_groups; + + return 0; +} + +static int pic64gx_gpio2_pinmux_set_mux(struct pinctrl_dev *pctrl_dev, unsigned int fsel, + unsigned int gsel) +{ + struct pic64gx_gpio2_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); + struct device *dev = pctrl->dev; + const struct pic64gx_gpio2_pin_group *group; + const struct pic64gx_gpio2_function *function; + + group = &pic64gx_gpio2_pin_groups[gsel]; + function = &pic64gx_gpio2_functions[fsel]; + + dev_dbg(dev, "Setting func %s mask %x setting %x\n", + function->name, group->mask, group->setting); + regmap_assign_bits(pctrl->regmap, PIC64GX_PINMUX_REG, group->mask, group->setting); + + return 0; +} + +static const struct pinmux_ops pic64gx_gpio2_pinmux_ops = { + .get_functions_count = pic64gx_gpio2_pinmux_get_funcs_count, + .get_function_name = pic64gx_gpio2_pinmux_get_func_name, + .get_function_groups = pic64gx_gpio2_pinmux_get_groups, + .set_mux = pic64gx_gpio2_pinmux_set_mux, +}; + +static int pic64gx_gpio2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pic64gx_gpio2_pinctrl *pctrl; + void __iomem *base; + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) { + dev_err(dev, "Failed get resource\n"); + return PTR_ERR(base); + } + + pctrl->regmap = devm_regmap_init_mmio(dev, base, &pic64gx_gpio2_regmap_config); + if (IS_ERR(pctrl->regmap)) { + dev_err(dev, "Failed to map regmap\n"); + return PTR_ERR(pctrl->regmap); + } + + pctrl->desc.name = dev_name(dev); + pctrl->desc.pins = pic64gx_gpio2_pins; + pctrl->desc.npins = ARRAY_SIZE(pic64gx_gpio2_pins); + pctrl->desc.pctlops = &pic64gx_gpio2_pinctrl_ops; + pctrl->desc.pmxops = &pic64gx_gpio2_pinmux_ops; + pctrl->desc.owner = THIS_MODULE; + + pctrl->dev = dev; + + platform_set_drvdata(pdev, pctrl); + + pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl); + if (IS_ERR(pctrl->pctrl)) + return PTR_ERR(pctrl->pctrl); + + return 0; +} + +static const struct of_device_id pic64gx_gpio2_of_match[] = { + { .compatible = "microchip,pic64gx-pinctrl-gpio2" }, + { } +}; +MODULE_DEVICE_TABLE(of, pic64gx_gpio2_of_match); + +static struct platform_driver pic64gx_gpio2_driver = { + .driver = { + .name = "pic64gx-pinctrl-gpio2", + .of_match_table = pic64gx_gpio2_of_match, + }, + .probe = pic64gx_gpio2_probe, +}; +module_platform_driver(pic64gx_gpio2_driver); + +MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>"); +MODULE_DESCRIPTION("pic64gx gpio2 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 7a68a6237649..e44ef262beec 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -105,6 +105,29 @@ .pull_type[3] = pull3, \ } +#define PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(id, pins, label, iom0, \ + iom1, iom2, iom3, \ + offset0, offset1, \ + offset2, offset3, drv0, \ + drv1, drv2, drv3) \ + { \ + .bank_num = id, \ + .nr_pins = pins, \ + .name = label, \ + .iomux = { \ + { .type = iom0, .offset = offset0 }, \ + { .type = iom1, .offset = offset1 }, \ + { .type = iom2, .offset = offset2 }, \ + { .type = iom3, .offset = offset3 }, \ + }, \ + .drv = { \ + { .drv_type = drv0, .offset = -1 }, \ + { .drv_type = drv1, .offset = -1 }, \ + { .drv_type = drv2, .offset = -1 }, \ + { .drv_type = drv3, .offset = -1 }, \ + }, \ + } + #define PIN_BANK_DRV_FLAGS(id, pins, label, type0, type1, type2, type3) \ { \ .bank_num = id, \ @@ -233,6 +256,35 @@ .pull_type[3] = pull3, \ } +#define PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(id, pins, \ + label, iom0, iom1, \ + iom2, iom3, offset0, \ + offset1, offset2, \ + offset3, drv0, drv1, \ + drv2, drv3, pull0, \ + pull1, pull2, pull3) \ + { \ + .bank_num = id, \ + .nr_pins = pins, \ + .name = label, \ + .iomux = { \ + { .type = iom0, .offset = offset0 }, \ + { .type = iom1, .offset = offset1 }, \ + { .type = iom2, .offset = offset2 }, \ + { .type = iom3, .offset = offset3 }, \ + }, \ + .drv = { \ + { .drv_type = drv0, .offset = -1 }, \ + { .drv_type = drv1, .offset = -1 }, \ + { .drv_type = drv2, .offset = -1 }, \ + { .drv_type = drv3, .offset = -1 }, \ + }, \ + .pull_type[0] = pull0, \ + .pull_type[1] = pull1, \ + .pull_type[2] = pull2, \ + .pull_type[3] = pull3, \ + } + #define PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, FLAG) \ { \ .bank_num = ID, \ @@ -1120,6 +1172,13 @@ static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin) else regmap = info->regmap_base; + if (ctrl->type == RK3506) { + if (bank->bank_num == 1) + regmap = info->regmap_ioc1; + else if (bank->bank_num == 4) + return 0; + } + /* get basic quadrupel of mux registers and the correct reg inside */ mux_type = bank->iomux[iomux_num].type; reg = bank->iomux[iomux_num].offset; @@ -1239,6 +1298,13 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) else regmap = info->regmap_base; + if (ctrl->type == RK3506) { + if (bank->bank_num == 1) + regmap = info->regmap_ioc1; + else if (bank->bank_num == 4) + return 0; + } + /* get basic quadrupel of mux registers and the correct reg inside */ mux_type = bank->iomux[iomux_num].type; reg = bank->iomux[iomux_num].offset; @@ -2003,6 +2069,262 @@ static int rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, return 0; } +#define RK3506_DRV_BITS_PER_PIN 8 +#define RK3506_DRV_PINS_PER_REG 2 +#define RK3506_DRV_GPIO0_A_OFFSET 0x100 +#define RK3506_DRV_GPIO0_D_OFFSET 0x830 +#define RK3506_DRV_GPIO1_OFFSET 0x140 +#define RK3506_DRV_GPIO2_OFFSET 0x180 +#define RK3506_DRV_GPIO3_OFFSET 0x1c0 +#define RK3506_DRV_GPIO4_OFFSET 0x840 + +static int rk3506_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + int ret = 0; + + switch (bank->bank_num) { + case 0: + *regmap = info->regmap_pmu; + if (pin_num > 24) { + ret = -EINVAL; + } else if (pin_num < 24) { + *reg = RK3506_DRV_GPIO0_A_OFFSET; + } else { + *reg = RK3506_DRV_GPIO0_D_OFFSET; + *bit = 3; + + return 0; + } + break; + + case 1: + *regmap = info->regmap_ioc1; + if (pin_num < 28) + *reg = RK3506_DRV_GPIO1_OFFSET; + else + ret = -EINVAL; + break; + + case 2: + *regmap = info->regmap_base; + if (pin_num < 17) + *reg = RK3506_DRV_GPIO2_OFFSET; + else + ret = -EINVAL; + break; + + case 3: + *regmap = info->regmap_base; + if (pin_num < 15) + *reg = RK3506_DRV_GPIO3_OFFSET; + else + ret = -EINVAL; + break; + + case 4: + *regmap = info->regmap_base; + if (pin_num < 8 || pin_num > 11) { + ret = -EINVAL; + } else { + *reg = RK3506_DRV_GPIO4_OFFSET; + *bit = 10; + + return 0; + } + break; + + default: + ret = -EINVAL; + break; + } + + if (ret) { + dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num); + + return ret; + } + + *reg += ((pin_num / RK3506_DRV_PINS_PER_REG) * 4); + *bit = pin_num % RK3506_DRV_PINS_PER_REG; + *bit *= RK3506_DRV_BITS_PER_PIN; + + return 0; +} + +#define RK3506_PULL_BITS_PER_PIN 2 +#define RK3506_PULL_PINS_PER_REG 8 +#define RK3506_PULL_GPIO0_A_OFFSET 0x200 +#define RK3506_PULL_GPIO0_D_OFFSET 0x830 +#define RK3506_PULL_GPIO1_OFFSET 0x210 +#define RK3506_PULL_GPIO2_OFFSET 0x220 +#define RK3506_PULL_GPIO3_OFFSET 0x230 +#define RK3506_PULL_GPIO4_OFFSET 0x840 + +static int rk3506_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + int ret = 0; + + switch (bank->bank_num) { + case 0: + *regmap = info->regmap_pmu; + if (pin_num > 24) { + ret = -EINVAL; + } else if (pin_num < 24) { + *reg = RK3506_PULL_GPIO0_A_OFFSET; + } else { + *reg = RK3506_PULL_GPIO0_D_OFFSET; + *bit = 5; + + return 0; + } + break; + + case 1: + *regmap = info->regmap_ioc1; + if (pin_num < 28) + *reg = RK3506_PULL_GPIO1_OFFSET; + else + ret = -EINVAL; + break; + + case 2: + *regmap = info->regmap_base; + if (pin_num < 17) + *reg = RK3506_PULL_GPIO2_OFFSET; + else + ret = -EINVAL; + break; + + case 3: + *regmap = info->regmap_base; + if (pin_num < 15) + *reg = RK3506_PULL_GPIO3_OFFSET; + else + ret = -EINVAL; + break; + + case 4: + *regmap = info->regmap_base; + if (pin_num < 8 || pin_num > 11) { + ret = -EINVAL; + } else { + *reg = RK3506_PULL_GPIO4_OFFSET; + *bit = 13; + + return 0; + } + break; + + default: + ret = -EINVAL; + break; + } + + if (ret) { + dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num); + + return ret; + } + + *reg += ((pin_num / RK3506_PULL_PINS_PER_REG) * 4); + *bit = pin_num % RK3506_PULL_PINS_PER_REG; + *bit *= RK3506_PULL_BITS_PER_PIN; + + return 0; +} + +#define RK3506_SMT_BITS_PER_PIN 1 +#define RK3506_SMT_PINS_PER_REG 8 +#define RK3506_SMT_GPIO0_A_OFFSET 0x400 +#define RK3506_SMT_GPIO0_D_OFFSET 0x830 +#define RK3506_SMT_GPIO1_OFFSET 0x410 +#define RK3506_SMT_GPIO2_OFFSET 0x420 +#define RK3506_SMT_GPIO3_OFFSET 0x430 +#define RK3506_SMT_GPIO4_OFFSET 0x840 + +static int rk3506_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, + struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + int ret = 0; + + switch (bank->bank_num) { + case 0: + *regmap = info->regmap_pmu; + if (pin_num > 24) { + ret = -EINVAL; + } else if (pin_num < 24) { + *reg = RK3506_SMT_GPIO0_A_OFFSET; + } else { + *reg = RK3506_SMT_GPIO0_D_OFFSET; + *bit = 9; + + return 0; + } + break; + + case 1: + *regmap = info->regmap_ioc1; + if (pin_num < 28) + *reg = RK3506_SMT_GPIO1_OFFSET; + else + ret = -EINVAL; + break; + + case 2: + *regmap = info->regmap_base; + if (pin_num < 17) + *reg = RK3506_SMT_GPIO2_OFFSET; + else + ret = -EINVAL; + break; + + case 3: + *regmap = info->regmap_base; + if (pin_num < 15) + *reg = RK3506_SMT_GPIO3_OFFSET; + else + ret = -EINVAL; + break; + + case 4: + *regmap = info->regmap_base; + if (pin_num < 8 || pin_num > 11) { + ret = -EINVAL; + } else { + *reg = RK3506_SMT_GPIO4_OFFSET; + *bit = 8; + + return 0; + } + break; + + default: + ret = -EINVAL; + break; + } + + if (ret) { + dev_err(info->dev, "unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num); + + return ret; + } + + *reg += ((pin_num / RK3506_SMT_PINS_PER_REG) * 4); + *bit = pin_num % RK3506_SMT_PINS_PER_REG; + *bit *= RK3506_SMT_BITS_PER_PIN; + + return 0; +} + #define RK3528_DRV_BITS_PER_PIN 8 #define RK3528_DRV_PINS_PER_REG 2 #define RK3528_DRV_GPIO0_OFFSET 0x100 @@ -2749,7 +3071,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, rmask_bits = RK3588_DRV_BITS_PER_PIN; ret = strength; goto config; - } else if (ctrl->type == RK3528 || + } else if (ctrl->type == RK3506 || + ctrl->type == RK3528 || ctrl->type == RK3562 || ctrl->type == RK3568) { rmask_bits = RK3568_DRV_BITS_PER_PIN; @@ -2828,12 +3151,37 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, case DRV_TYPE_IO_1V8_ONLY: rmask_bits = RK3288_DRV_BITS_PER_PIN; break; + case DRV_TYPE_IO_LEVEL_2_BIT: + ret = regmap_read(regmap, reg, &data); + if (ret) + return ret; + data >>= bit; + + return data & 0x3; + case DRV_TYPE_IO_LEVEL_8_BIT: + ret = regmap_read(regmap, reg, &data); + if (ret) + return ret; + data >>= bit; + data &= (1 << 8) - 1; + + ret = hweight8(data); + if (ret > 0) + return ret - 1; + else + return -EINVAL; default: dev_err(dev, "unsupported pinctrl drive type: %d\n", drv_type); return -EINVAL; } config: + if (ctrl->type == RK3506) { + if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) { + rmask_bits = 2; + ret = strength; + } + } /* enable the write to the equivalent lower bits */ data = ((1 << rmask_bits) - 1) << (bit + 16); rmask = data | (data >> 16); @@ -2957,6 +3305,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, case RK3328: case RK3368: case RK3399: + case RK3506: case RK3528: case RK3562: case RK3568: @@ -3077,6 +3426,10 @@ static int rockchip_get_schmitt(struct rockchip_pin_bank *bank, int pin_num) break; } + if (ctrl->type == RK3506) + if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) + return data & 0x3; + return data & 0x1; } @@ -3112,6 +3465,14 @@ static int rockchip_set_schmitt(struct rockchip_pin_bank *bank, break; } + if (ctrl->type == RK3506) { + if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) { + data = 0x3 << (bit + 16); + rmask = data | (data >> 16); + data |= ((enable ? 0x3 : 0) << bit); + } + } + return regmap_update_bits(regmap, reg, rmask, data); } @@ -3227,6 +3588,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, case RK3328: case RK3368: case RK3399: + case RK3506: case RK3528: case RK3562: case RK3568: @@ -3880,13 +4242,10 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) } /* try to find the optional reference to the pmu syscon */ - node = of_parse_phandle(np, "rockchip,pmu", 0); - if (node) { - info->regmap_pmu = syscon_node_to_regmap(node); - of_node_put(node); - if (IS_ERR(info->regmap_pmu)) - return PTR_ERR(info->regmap_pmu); - } + info->regmap_pmu = syscon_regmap_lookup_by_phandle_optional(np, "rockchip,pmu"); + + /* try to find the optional reference to the ioc1 syscon */ + info->regmap_ioc1 = syscon_regmap_lookup_by_phandle_optional(np, "rockchip,ioc1"); ret = rockchip_pinctrl_register(pdev, info); if (ret) @@ -4350,6 +4709,71 @@ static struct rockchip_pin_ctrl rk3399_pin_ctrl = { .drv_calc_reg = rk3399_calc_drv_reg_and_bit, }; +static struct rockchip_pin_bank rk3506_pin_banks[] = { + PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(0, 32, "gpio0", + IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU, + IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU, + IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU, + IOMUX_WIDTH_2BIT | IOMUX_SOURCE_PMU, + 0x0, 0x8, 0x10, 0x830, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_2_BIT, + 0, 0, 0, 1), + PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(1, 32, "gpio1", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x20, 0x28, 0x30, 0x38, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT), + PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(2, 32, "gpio2", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x40, 0x48, 0x50, 0x58, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT), + PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS(3, 32, "gpio3", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x60, 0x68, 0x70, 0x78, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, + DRV_TYPE_IO_LEVEL_8_BIT), + PIN_BANK_IOMUX_FLAGS_OFFSET_DRV_FLAGS_PULL_FLAGS(4, 32, "gpio4", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x80, 0x88, 0x90, 0x98, + DRV_TYPE_IO_LEVEL_2_BIT, + DRV_TYPE_IO_LEVEL_2_BIT, + DRV_TYPE_IO_LEVEL_2_BIT, + DRV_TYPE_IO_LEVEL_2_BIT, + 1, 1, 1, 1), +}; + +static struct rockchip_pin_ctrl rk3506_pin_ctrl __maybe_unused = { + .pin_banks = rk3506_pin_banks, + .nr_banks = ARRAY_SIZE(rk3506_pin_banks), + .label = "RK3506-GPIO", + .type = RK3506, + .pull_calc_reg = rk3506_calc_pull_reg_and_bit, + .drv_calc_reg = rk3506_calc_drv_reg_and_bit, + .schmitt_calc_reg = rk3506_calc_schmitt_reg_and_bit, +}; + static struct rockchip_pin_bank rk3528_pin_banks[] = { PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_WIDTH_4BIT, @@ -4560,6 +4984,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = { .data = &rk3368_pin_ctrl }, { .compatible = "rockchip,rk3399-pinctrl", .data = &rk3399_pin_ctrl }, + { .compatible = "rockchip,rk3506-pinctrl", + .data = &rk3506_pin_ctrl }, { .compatible = "rockchip,rk3528-pinctrl", .data = &rk3528_pin_ctrl }, { .compatible = "rockchip,rk3562-pinctrl", diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h index 35cd38079d1e..4f4aff42a80a 100644 --- a/drivers/pinctrl/pinctrl-rockchip.h +++ b/drivers/pinctrl/pinctrl-rockchip.h @@ -196,6 +196,7 @@ enum rockchip_pinctrl_type { RK3328, RK3368, RK3399, + RK3506, RK3528, RK3562, RK3568, @@ -260,6 +261,8 @@ enum rockchip_pin_drv_type { DRV_TYPE_IO_1V8_ONLY, DRV_TYPE_IO_1V8_3V0_AUTO, DRV_TYPE_IO_3V3_ONLY, + DRV_TYPE_IO_LEVEL_2_BIT, + DRV_TYPE_IO_LEVEL_8_BIT, DRV_TYPE_MAX }; @@ -458,6 +461,7 @@ struct rockchip_pinctrl { int reg_size; struct regmap *regmap_pull; struct regmap *regmap_pmu; + struct regmap *regmap_ioc1; struct device *dev; struct rockchip_pin_ctrl *ctrl; struct pinctrl_desc pctl; diff --git a/drivers/pinctrl/pinctrl-scmi.c b/drivers/pinctrl/pinctrl-scmi.c index d14528b9aa31..af3ac031e362 100644 --- a/drivers/pinctrl/pinctrl-scmi.c +++ b/drivers/pinctrl/pinctrl-scmi.c @@ -40,8 +40,6 @@ struct scmi_pinctrl { struct pinctrl_desc pctl_desc; struct pinfunction *functions; unsigned int nr_functions; - struct pinctrl_pin_desc *pins; - unsigned int nr_pins; }; static int pinctrl_scmi_get_groups_count(struct pinctrl_dev *pctldev) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 6d580aa282ec..998f23d6c317 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -485,7 +485,8 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev, struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_function *func; enum pin_config_param param; - unsigned offset = 0, data = 0, i, j, ret; + unsigned offset = 0, data = 0, i, j; + int ret; ret = pcs_get_function(pctldev, pin, &func); if (ret) @@ -549,9 +550,9 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev, { struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_function *func; - unsigned offset = 0, shift = 0, i, data, ret; + unsigned offset = 0, shift = 0, i, data; u32 arg; - int j; + int j, ret; enum pin_config_param param; ret = pcs_get_function(pctldev, pin, &func); diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm index 69a5b47adedc..3e9e02774001 100644 --- a/drivers/pinctrl/qcom/Kconfig.msm +++ b/drivers/pinctrl/qcom/Kconfig.msm @@ -92,6 +92,14 @@ config PINCTRL_IPQ9574 Qualcomm Technologies Inc. IPQ9574 platform. Select this for IPQ9574. +config PINCTRL_KAANAPALI + tristate "Qualcomm Technologies Inc Kaanapali pin controller driver" + depends on ARM64 || COMPILE_TEST + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm Technologies Inc TLMM block found on the Qualcomm + Technologies Inc Kaanapali platform. + config PINCTRL_MSM8226 tristate "Qualcomm 8226 pin controller driver" depends on ARM || COMPILE_TEST diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 567d3051e760..748b17a77b2c 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PINCTRL_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_PINCTRL_IPQ8074) += pinctrl-ipq8074.o obj-$(CONFIG_PINCTRL_IPQ6018) += pinctrl-ipq6018.o obj-$(CONFIG_PINCTRL_IPQ9574) += pinctrl-ipq9574.o +obj-$(CONFIG_PINCTRL_KAANAPALI) += pinctrl-kaanapali.o obj-$(CONFIG_PINCTRL_MSM8226) += pinctrl-msm8226.o obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o diff --git a/drivers/pinctrl/qcom/pinctrl-glymur.c b/drivers/pinctrl/qcom/pinctrl-glymur.c index 9913f98e9531..335005084b6b 100644 --- a/drivers/pinctrl/qcom/pinctrl-glymur.c +++ b/drivers/pinctrl/qcom/pinctrl-glymur.c @@ -1316,7 +1316,7 @@ static const char *const wcn_sw_ctrl_groups[] = { }; static const struct pinfunction glymur_functions[] = { - MSM_PIN_FUNCTION(gpio), + MSM_GPIO_PIN_FUNCTION(gpio), MSM_PIN_FUNCTION(resout_gpio_n), MSM_PIN_FUNCTION(aoss_cti), MSM_PIN_FUNCTION(asc_cci), @@ -1342,7 +1342,7 @@ static const struct pinfunction glymur_functions[] = { MSM_PIN_FUNCTION(edp0_hot), MSM_PIN_FUNCTION(edp0_lcd), MSM_PIN_FUNCTION(edp1_lcd), - MSM_PIN_FUNCTION(egpio), + MSM_GPIO_PIN_FUNCTION(egpio), MSM_PIN_FUNCTION(eusb_ac_en), MSM_PIN_FUNCTION(gcc_gp1), MSM_PIN_FUNCTION(gcc_gp2), @@ -1743,7 +1743,7 @@ static const struct msm_pinctrl_soc_data glymur_tlmm = { }; static const struct of_device_id glymur_tlmm_of_match[] = { - { .compatible = "qcom,glymur-tlmm", .data = &glymur_tlmm }, + { .compatible = "qcom,glymur-tlmm", }, { } }; diff --git a/drivers/pinctrl/qcom/pinctrl-kaanapali.c b/drivers/pinctrl/qcom/pinctrl-kaanapali.c new file mode 100644 index 000000000000..364e6d997337 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-kaanapali.c @@ -0,0 +1,1803 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "pinctrl-msm.h" + +#define REG_SIZE 0x1000 +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \ + { \ + .grp = PINCTRL_PINGROUP("gpio" #id, \ + gpio##id##_pins, \ + ARRAY_SIZE(gpio##id##_pins)), \ + .funcs = (int[]){ \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9, \ + msm_mux_##f10, \ + msm_mux_##f11 /* egpio mode */ \ + }, \ + .nfuncs = 12, \ + .ctl_reg = REG_SIZE * id, \ + .io_reg = 0x4 + REG_SIZE * id, \ + .intr_cfg_reg = 0x8 + REG_SIZE * id, \ + .intr_status_reg = 0xc + REG_SIZE * id, \ + .intr_target_reg = 0x8 + REG_SIZE * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .egpio_enable = 12, \ + .egpio_present = 11, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_wakeup_present_bit = 6, \ + .intr_wakeup_enable_bit = 7, \ + .intr_target_bit = 8, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define UFS_RESET(pg_name, ctl, io) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = io, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +static const struct pinctrl_pin_desc kaanapali_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + PINCTRL_PIN(147, "GPIO_147"), + PINCTRL_PIN(148, "GPIO_148"), + PINCTRL_PIN(149, "GPIO_149"), + PINCTRL_PIN(150, "GPIO_150"), + PINCTRL_PIN(151, "GPIO_151"), + PINCTRL_PIN(152, "GPIO_152"), + PINCTRL_PIN(153, "GPIO_153"), + PINCTRL_PIN(154, "GPIO_154"), + PINCTRL_PIN(155, "GPIO_155"), + PINCTRL_PIN(156, "GPIO_156"), + PINCTRL_PIN(157, "GPIO_157"), + PINCTRL_PIN(158, "GPIO_158"), + PINCTRL_PIN(159, "GPIO_159"), + PINCTRL_PIN(160, "GPIO_160"), + PINCTRL_PIN(161, "GPIO_161"), + PINCTRL_PIN(162, "GPIO_162"), + PINCTRL_PIN(163, "GPIO_163"), + PINCTRL_PIN(164, "GPIO_164"), + PINCTRL_PIN(165, "GPIO_165"), + PINCTRL_PIN(166, "GPIO_166"), + PINCTRL_PIN(167, "GPIO_167"), + PINCTRL_PIN(168, "GPIO_168"), + PINCTRL_PIN(169, "GPIO_169"), + PINCTRL_PIN(170, "GPIO_170"), + PINCTRL_PIN(171, "GPIO_171"), + PINCTRL_PIN(172, "GPIO_172"), + PINCTRL_PIN(173, "GPIO_173"), + PINCTRL_PIN(174, "GPIO_174"), + PINCTRL_PIN(175, "GPIO_175"), + PINCTRL_PIN(176, "GPIO_176"), + PINCTRL_PIN(177, "GPIO_177"), + PINCTRL_PIN(178, "GPIO_178"), + PINCTRL_PIN(179, "GPIO_179"), + PINCTRL_PIN(180, "GPIO_180"), + PINCTRL_PIN(181, "GPIO_181"), + PINCTRL_PIN(182, "GPIO_182"), + PINCTRL_PIN(183, "GPIO_183"), + PINCTRL_PIN(184, "GPIO_184"), + PINCTRL_PIN(185, "GPIO_185"), + PINCTRL_PIN(186, "GPIO_186"), + PINCTRL_PIN(187, "GPIO_187"), + PINCTRL_PIN(188, "GPIO_188"), + PINCTRL_PIN(189, "GPIO_189"), + PINCTRL_PIN(190, "GPIO_190"), + PINCTRL_PIN(191, "GPIO_191"), + PINCTRL_PIN(192, "GPIO_192"), + PINCTRL_PIN(193, "GPIO_193"), + PINCTRL_PIN(194, "GPIO_194"), + PINCTRL_PIN(195, "GPIO_195"), + PINCTRL_PIN(196, "GPIO_196"), + PINCTRL_PIN(197, "GPIO_197"), + PINCTRL_PIN(198, "GPIO_198"), + PINCTRL_PIN(199, "GPIO_199"), + PINCTRL_PIN(200, "GPIO_200"), + PINCTRL_PIN(201, "GPIO_201"), + PINCTRL_PIN(202, "GPIO_202"), + PINCTRL_PIN(203, "GPIO_203"), + PINCTRL_PIN(204, "GPIO_204"), + PINCTRL_PIN(205, "GPIO_205"), + PINCTRL_PIN(206, "GPIO_206"), + PINCTRL_PIN(207, "GPIO_207"), + PINCTRL_PIN(208, "GPIO_208"), + PINCTRL_PIN(209, "GPIO_209"), + PINCTRL_PIN(210, "GPIO_210"), + PINCTRL_PIN(211, "GPIO_211"), + PINCTRL_PIN(212, "GPIO_212"), + PINCTRL_PIN(213, "GPIO_213"), + PINCTRL_PIN(214, "GPIO_214"), + PINCTRL_PIN(215, "GPIO_215"), + PINCTRL_PIN(216, "GPIO_216"), + PINCTRL_PIN(217, "UFS_RESET"), + PINCTRL_PIN(218, "SDC2_CLK"), + PINCTRL_PIN(219, "SDC2_CMD"), + PINCTRL_PIN(220, "SDC2_DATA"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); +DECLARE_MSM_GPIO_PINS(133); +DECLARE_MSM_GPIO_PINS(134); +DECLARE_MSM_GPIO_PINS(135); +DECLARE_MSM_GPIO_PINS(136); +DECLARE_MSM_GPIO_PINS(137); +DECLARE_MSM_GPIO_PINS(138); +DECLARE_MSM_GPIO_PINS(139); +DECLARE_MSM_GPIO_PINS(140); +DECLARE_MSM_GPIO_PINS(141); +DECLARE_MSM_GPIO_PINS(142); +DECLARE_MSM_GPIO_PINS(143); +DECLARE_MSM_GPIO_PINS(144); +DECLARE_MSM_GPIO_PINS(145); +DECLARE_MSM_GPIO_PINS(146); +DECLARE_MSM_GPIO_PINS(147); +DECLARE_MSM_GPIO_PINS(148); +DECLARE_MSM_GPIO_PINS(149); +DECLARE_MSM_GPIO_PINS(150); +DECLARE_MSM_GPIO_PINS(151); +DECLARE_MSM_GPIO_PINS(152); +DECLARE_MSM_GPIO_PINS(153); +DECLARE_MSM_GPIO_PINS(154); +DECLARE_MSM_GPIO_PINS(155); +DECLARE_MSM_GPIO_PINS(156); +DECLARE_MSM_GPIO_PINS(157); +DECLARE_MSM_GPIO_PINS(158); +DECLARE_MSM_GPIO_PINS(159); +DECLARE_MSM_GPIO_PINS(160); +DECLARE_MSM_GPIO_PINS(161); +DECLARE_MSM_GPIO_PINS(162); +DECLARE_MSM_GPIO_PINS(163); +DECLARE_MSM_GPIO_PINS(164); +DECLARE_MSM_GPIO_PINS(165); +DECLARE_MSM_GPIO_PINS(166); +DECLARE_MSM_GPIO_PINS(167); +DECLARE_MSM_GPIO_PINS(168); +DECLARE_MSM_GPIO_PINS(169); +DECLARE_MSM_GPIO_PINS(170); +DECLARE_MSM_GPIO_PINS(171); +DECLARE_MSM_GPIO_PINS(172); +DECLARE_MSM_GPIO_PINS(173); +DECLARE_MSM_GPIO_PINS(174); +DECLARE_MSM_GPIO_PINS(175); +DECLARE_MSM_GPIO_PINS(176); +DECLARE_MSM_GPIO_PINS(177); +DECLARE_MSM_GPIO_PINS(178); +DECLARE_MSM_GPIO_PINS(179); +DECLARE_MSM_GPIO_PINS(180); +DECLARE_MSM_GPIO_PINS(181); +DECLARE_MSM_GPIO_PINS(182); +DECLARE_MSM_GPIO_PINS(183); +DECLARE_MSM_GPIO_PINS(184); +DECLARE_MSM_GPIO_PINS(185); +DECLARE_MSM_GPIO_PINS(186); +DECLARE_MSM_GPIO_PINS(187); +DECLARE_MSM_GPIO_PINS(188); +DECLARE_MSM_GPIO_PINS(189); +DECLARE_MSM_GPIO_PINS(190); +DECLARE_MSM_GPIO_PINS(191); +DECLARE_MSM_GPIO_PINS(192); +DECLARE_MSM_GPIO_PINS(193); +DECLARE_MSM_GPIO_PINS(194); +DECLARE_MSM_GPIO_PINS(195); +DECLARE_MSM_GPIO_PINS(196); +DECLARE_MSM_GPIO_PINS(197); +DECLARE_MSM_GPIO_PINS(198); +DECLARE_MSM_GPIO_PINS(199); +DECLARE_MSM_GPIO_PINS(200); +DECLARE_MSM_GPIO_PINS(201); +DECLARE_MSM_GPIO_PINS(202); +DECLARE_MSM_GPIO_PINS(203); +DECLARE_MSM_GPIO_PINS(204); +DECLARE_MSM_GPIO_PINS(205); +DECLARE_MSM_GPIO_PINS(206); +DECLARE_MSM_GPIO_PINS(207); +DECLARE_MSM_GPIO_PINS(208); +DECLARE_MSM_GPIO_PINS(209); +DECLARE_MSM_GPIO_PINS(210); +DECLARE_MSM_GPIO_PINS(211); +DECLARE_MSM_GPIO_PINS(212); +DECLARE_MSM_GPIO_PINS(213); +DECLARE_MSM_GPIO_PINS(214); +DECLARE_MSM_GPIO_PINS(215); +DECLARE_MSM_GPIO_PINS(216); + +static const unsigned int ufs_reset_pins[] = { 217 }; +static const unsigned int sdc2_clk_pins[] = { 218 }; +static const unsigned int sdc2_cmd_pins[] = { 219 }; +static const unsigned int sdc2_data_pins[] = { 220 }; + +enum kaanapali_functions { + msm_mux_gpio, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_usb, + msm_mux_audio_ext_mclk0, + msm_mux_audio_ext_mclk1, + msm_mux_audio_ref_clk, + msm_mux_cam_asc_mclk2, + msm_mux_cam_asc_mclk4, + msm_mux_cam_mclk, + msm_mux_cci_async_in, + msm_mux_cci_i2c_scl, + msm_mux_cci_i2c_sda, + msm_mux_cci_timer, + msm_mux_cmu_rng, + msm_mux_coex_uart1_rx, + msm_mux_coex_uart1_tx, + msm_mux_coex_uart2_rx, + msm_mux_coex_uart2_tx, + msm_mux_dbg_out_clk, + msm_mux_ddr_bist_complete, + msm_mux_ddr_bist_fail, + msm_mux_ddr_bist_start, + msm_mux_ddr_bist_stop, + msm_mux_ddr_pxi0, + msm_mux_ddr_pxi1, + msm_mux_ddr_pxi2, + msm_mux_ddr_pxi3, + msm_mux_dp_hot, + msm_mux_egpio, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_gnss_adc0, + msm_mux_gnss_adc1, + msm_mux_i2chub0_se0, + msm_mux_i2chub0_se1, + msm_mux_i2chub0_se2, + msm_mux_i2chub0_se3, + msm_mux_i2chub0_se4, + msm_mux_i2s0_data0, + msm_mux_i2s0_data1, + msm_mux_i2s0_sck, + msm_mux_i2s0_ws, + msm_mux_i2s1_data0, + msm_mux_i2s1_data1, + msm_mux_i2s1_sck, + msm_mux_i2s1_ws, + msm_mux_ibi_i3c, + msm_mux_jitter_bist, + msm_mux_mdp_esync0_out, + msm_mux_mdp_esync1_out, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0_out, + msm_mux_mdp_vsync1_out, + msm_mux_mdp_vsync2_out, + msm_mux_mdp_vsync3_out, + msm_mux_mdp_vsync5_out, + msm_mux_mdp_vsync_e, + msm_mux_nav_gpio0, + msm_mux_nav_gpio1, + msm_mux_nav_gpio2, + msm_mux_nav_gpio3, + msm_mux_pcie0_clk_req_n, + msm_mux_phase_flag, + msm_mux_pll_bist_sync, + msm_mux_pll_clk_aux, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_qdss_cti, + msm_mux_qdss_gpio_traceclk, + msm_mux_qdss_gpio_tracectl, + msm_mux_qdss_gpio_tracedata, + msm_mux_qlink_big_enable, + msm_mux_qlink_big_request, + msm_mux_qlink_little_enable, + msm_mux_qlink_little_request, + msm_mux_qlink_wmss, + msm_mux_qspi0, + msm_mux_qspi1, + msm_mux_qspi2, + msm_mux_qspi3, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qup1_se0, + msm_mux_qup1_se1, + msm_mux_qup1_se2, + msm_mux_qup1_se3, + msm_mux_qup1_se4, + msm_mux_qup1_se5, + msm_mux_qup1_se6, + msm_mux_qup1_se7, + msm_mux_qup2_se0, + msm_mux_qup2_se1, + msm_mux_qup2_se2, + msm_mux_qup2_se3, + msm_mux_qup2_se4, + msm_mux_qup3_se0, + msm_mux_qup3_se1, + msm_mux_qup3_se2, + msm_mux_qup3_se3, + msm_mux_qup3_se4, + msm_mux_qup3_se5, + msm_mux_qup4_se0, + msm_mux_qup4_se1, + msm_mux_qup4_se2, + msm_mux_qup4_se3, + msm_mux_qup4_se4, + msm_mux_sd_write_protect, + msm_mux_sdc40, + msm_mux_sdc41, + msm_mux_sdc42, + msm_mux_sdc43, + msm_mux_sdc4_clk, + msm_mux_sdc4_cmd, + msm_mux_sys_throttle, + msm_mux_tb_trig_sdc2, + msm_mux_tb_trig_sdc4, + msm_mux_tmess_prng0, + msm_mux_tmess_prng1, + msm_mux_tmess_prng2, + msm_mux_tmess_prng3, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_tsense_pwm3, + msm_mux_tsense_pwm4, + msm_mux_tsense_pwm5, + msm_mux_tsense_pwm6, + msm_mux_tsense_pwm7, + msm_mux_uim0_clk, + msm_mux_uim0_data, + msm_mux_uim0_present, + msm_mux_uim0_reset, + msm_mux_uim1_clk, + msm_mux_uim1_data, + msm_mux_uim1_present, + msm_mux_uim1_reset, + msm_mux_usb0_hs, + msm_mux_usb_phy, + msm_mux_vfr_0, + msm_mux_vfr_1, + msm_mux_vsense_trigger_mirnat, + msm_mux_wcn_sw, + msm_mux_wcn_sw_ctrl, + msm_mux__, +}; + +static const char *const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", + "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", + "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", + "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", + "gpio48", "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", + "gpio54", "gpio55", "gpio56", "gpio57", "gpio58", "gpio59", + "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65", + "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", + "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", + "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", + "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", + "gpio96", "gpio97", "gpio98", "gpio99", "gpio100", "gpio101", + "gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107", + "gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113", + "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", "gpio119", + "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125", + "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", + "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137", + "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143", + "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", "gpio149", + "gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155", + "gpio156", "gpio157", "gpio158", "gpio159", "gpio160", "gpio161", + "gpio162", "gpio163", "gpio164", "gpio165", "gpio166", "gpio167", + "gpio168", "gpio169", "gpio170", "gpio171", "gpio172", "gpio173", + "gpio174", "gpio175", "gpio176", "gpio177", "gpio178", "gpio179", + "gpio180", "gpio181", "gpio182", "gpio183", "gpio184", "gpio185", + "gpio186", "gpio187", "gpio188", "gpio189", "gpio190", "gpio191", + "gpio192", "gpio193", "gpio194", "gpio195", "gpio196", "gpio197", + "gpio198", "gpio199", "gpio200", "gpio201", "gpio202", "gpio203", + "gpio204", "gpio205", "gpio206", "gpio207", "gpio208", "gpio209", + "gpio210", "gpio211", "gpio212", "gpio213", "gpio214", "gpio215", + "gpio216", +}; + +static const char *const aoss_cti_groups[] = { + "gpio74", "gpio75", "gpio76", "gpio77", +}; + +static const char *const atest_char_groups[] = { + "gpio126", "gpio127", "gpio128", "gpio129", "gpio133", +}; + +static const char *const atest_usb_groups[] = { + "gpio70", "gpio71", "gpio72", "gpio73", "gpio129", +}; + +static const char *const audio_ext_mclk0_groups[] = { + "gpio121", +}; + +static const char *const audio_ext_mclk1_groups[] = { + "gpio120", +}; + +static const char *const audio_ref_clk_groups[] = { + "gpio120", +}; + +static const char *const cam_asc_mclk2_groups[] = { + "gpio91", +}; + +static const char *const cam_asc_mclk4_groups[] = { + "gpio93", +}; + +static const char *const cam_mclk_groups[] = { + "gpio89", "gpio90", "gpio92", "gpio94", "gpio95", "gpio96", +}; + +static const char *const cci_async_in_groups[] = { + "gpio10", "gpio11", "gpio15", +}; + +static const char *const cci_i2c_scl_groups[] = { + "gpio110", "gpio112", "gpio114", "gpio116", "gpio149", "gpio160", +}; + +static const char *const cci_i2c_sda_groups[] = { + "gpio107", "gpio108", "gpio109", "gpio111", "gpio113", "gpio115", +}; + +static const char *const cci_timer_groups[] = { + "gpio105", "gpio106", "gpio107", "gpio159", "gpio160", +}; + +static const char *const cmu_rng_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", "gpio144", "gpio145", + "gpio146", "gpio147", +}; + +static const char *const coex_uart1_rx_groups[] = { + "gpio144", +}; + +static const char *const coex_uart1_tx_groups[] = { + "gpio145", +}; + +static const char *const coex_uart2_rx_groups[] = { + "gpio146", +}; + +static const char *const coex_uart2_tx_groups[] = { + "gpio147", +}; + +static const char *const dbg_out_clk_groups[] = { + "gpio42", +}; + +static const char *const ddr_bist_complete_groups[] = { + "gpio44", +}; + +static const char *const ddr_bist_fail_groups[] = { + "gpio40", +}; + +static const char *const ddr_bist_start_groups[] = { + "gpio41", +}; + +static const char *const ddr_bist_stop_groups[] = { + "gpio45", +}; + +static const char *const ddr_pxi0_groups[] = { + "gpio54", "gpio55", +}; + +static const char *const ddr_pxi1_groups[] = { + "gpio44", "gpio45", +}; + +static const char *const ddr_pxi2_groups[] = { + "gpio43", "gpio52", +}; + +static const char *const ddr_pxi3_groups[] = { + "gpio46", "gpio53", +}; + +static const char *const dp_hot_groups[] = { + "gpio47", +}; + +static const char *const egpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio28", "gpio29", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio163", "gpio164", "gpio165", "gpio166", + "gpio167", "gpio168", "gpio169", "gpio170", "gpio171", "gpio172", + "gpio173", "gpio174", "gpio175", "gpio176", "gpio177", "gpio178", + "gpio179", "gpio180", "gpio181", "gpio182", "gpio183", "gpio184", + "gpio185", "gpio186", "gpio187", "gpio188", "gpio189", "gpio190", + "gpio191", "gpio192", "gpio193", "gpio194", "gpio195", "gpio196", + "gpio197", "gpio198", "gpio199", "gpio200", "gpio201", "gpio202", + "gpio203", "gpio204", "gpio205", "gpio206", "gpio207", "gpio208", + "gpio209", "gpio210", "gpio211", "gpio212", "gpio213", "gpio214", + "gpio215", "gpio216", +}; + +static const char *const gcc_gp1_groups[] = { + "gpio130", "gpio158", +}; + +static const char *const gcc_gp2_groups[] = { + "gpio86", "gpio131", +}; + +static const char *const gcc_gp3_groups[] = { + "gpio87", "gpio132", +}; + +static const char *const gnss_adc0_groups[] = { + "gpio40", "gpio41", +}; + +static const char *const gnss_adc1_groups[] = { + "gpio42", "gpio77", +}; + +static const char *const i2chub0_se0_groups[] = { + "gpio66", "gpio67", +}; + +static const char *const i2chub0_se1_groups[] = { + "gpio78", "gpio79", +}; + +static const char *const i2chub0_se2_groups[] = { + "gpio68", "gpio69", +}; + +static const char *const i2chub0_se3_groups[] = { + "gpio70", "gpio71", +}; + +static const char *const i2chub0_se4_groups[] = { + "gpio72", "gpio73", +}; + +static const char *const i2s0_data0_groups[] = { + "gpio123", +}; + +static const char *const i2s0_data1_groups[] = { + "gpio124", +}; + +static const char *const i2s0_sck_groups[] = { + "gpio122", +}; + +static const char *const i2s0_ws_groups[] = { + "gpio125", +}; + +static const char *const i2s1_data0_groups[] = { + "gpio118", +}; + +static const char *const i2s1_data1_groups[] = { + "gpio120", +}; + +static const char *const i2s1_sck_groups[] = { + "gpio117", +}; + +static const char *const i2s1_ws_groups[] = { + "gpio119", +}; + +static const char *const ibi_i3c_groups[] = { + "gpio0", "gpio1", "gpio4", "gpio5", "gpio8", "gpio9", + "gpio12", "gpio13", "gpio28", "gpio29", "gpio32", "gpio33", + "gpio36", "gpio37", "gpio48", "gpio49", "gpio60", "gpio61", +}; + +static const char *const jitter_bist_groups[] = { + "gpio73", +}; + +static const char *const mdp_esync0_out_groups[] = { + "gpio88", +}; + +static const char *const mdp_esync1_out_groups[] = { + "gpio100", +}; + +static const char *const mdp_vsync_groups[] = { + "gpio86", "gpio87", "gpio97", "gpio98", +}; + +static const char *const mdp_vsync0_out_groups[] = { + "gpio86", +}; + +static const char *const mdp_vsync1_out_groups[] = { + "gpio86", +}; + +static const char *const mdp_vsync2_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync3_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync5_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync_e_groups[] = { + "gpio88", +}; + +static const char *const nav_gpio0_groups[] = { + "gpio150", +}; + +static const char *const nav_gpio1_groups[] = { + "gpio151", +}; + +static const char *const nav_gpio2_groups[] = { + "gpio148", +}; + +static const char *const nav_gpio3_groups[] = { + "gpio150", +}; + +static const char *const pcie0_clk_req_n_groups[] = { + "gpio103", +}; + +static const char *const phase_flag_groups[] = { + "gpio117", "gpio118", "gpio119", "gpio123", "gpio124", "gpio125", + "gpio169", "gpio170", "gpio171", "gpio172", "gpio173", "gpio175", + "gpio176", "gpio179", "gpio180", "gpio181", "gpio184", "gpio185", + "gpio192", "gpio196", "gpio197", "gpio198", "gpio199", "gpio204", + "gpio206", "gpio207", "gpio208", "gpio210", "gpio211", "gpio214", + "gpio215", "gpio216", +}; + +static const char *const pll_bist_sync_groups[] = { + "gpio104", +}; + +static const char *const pll_clk_aux_groups[] = { + "gpio94", +}; + +static const char *const prng_rosc0_groups[] = { + "gpio85", +}; + +static const char *const prng_rosc1_groups[] = { + "gpio64", +}; + +static const char *const prng_rosc2_groups[] = { + "gpio65", +}; + +static const char *const prng_rosc3_groups[] = { + "gpio66", +}; + +static const char *const qdss_cti_groups[] = { + "gpio27", "gpio31", "gpio72", "gpio73", "gpio82", "gpio83", + "gpio155", "gpio158", +}; + +static const char *const qdss_gpio_traceclk_groups[] = { + "gpio128", +}; + +static const char *const qdss_gpio_tracectl_groups[] = { + "gpio127", +}; + +static const char *const qdss_gpio_tracedata_groups[] = { + "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", + "gpio62", "gpio63", "gpio68", "gpio69", "gpio126", "gpio129", + "gpio130", "gpio131", "gpio132", "gpio133", +}; + +static const char *const qlink_big_enable_groups[] = { + "gpio156", +}; + +static const char *const qlink_big_request_groups[] = { + "gpio155", +}; + +static const char *const qlink_little_enable_groups[] = { + "gpio153", +}; + +static const char *const qlink_little_request_groups[] = { + "gpio152", +}; + +static const char *const qlink_wmss_groups[] = { + "gpio154", +}; + +static const char *const qspi0_groups[] = { + "gpio80", +}; + +static const char *const qspi1_groups[] = { + "gpio147", +}; + +static const char *const qspi2_groups[] = { + "gpio81", +}; + +static const char *const qspi3_groups[] = { + "gpio82", +}; + +static const char *const qspi_clk_groups[] = { + "gpio83", +}; + +static const char *const qspi_cs_groups[] = { + "gpio146", "gpio148", +}; + +static const char *const qup1_se0_groups[] = { + "gpio80", "gpio81", "gpio82", "gpio83", +}; + +static const char *const qup1_se1_groups[] = { + "gpio74", "gpio75", "gpio76", "gpio77", +}; + +static const char *const qup1_se2_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", "gpio130", "gpio131", "gpio132", +}; + +static const char *const qup1_se3_groups[] = { + "gpio44", "gpio45", "gpio46", "gpio47", +}; + +static const char *const qup1_se4_groups[] = { + "gpio36", "gpio37", "gpio38", "gpio39", +}; + +static const char *const qup1_se5_groups[] = { + "gpio52", "gpio53", "gpio54", "gpio55", +}; + +static const char *const qup1_se6_groups[] = { + "gpio56", "gpio57", "gpio58", "gpio59", +}; + +static const char *const qup1_se7_groups[] = { + "gpio60", "gpio61", "gpio62", "gpio63", +}; + +static const char *const qup2_se0_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; + +static const char *const qup2_se1_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; + +static const char *const qup2_se2_groups[] = { + "gpio117", "gpio118", "gpio119", "gpio120", +}; + +static const char *const qup2_se3_groups[] = { + "gpio122", "gpio123", "gpio124", "gpio125", +}; + +static const char *const qup2_se4_groups[] = { + "gpio208", "gpio209", +}; + +static const char *const qup3_se0_groups[] = { + "gpio64", "gpio65", +}; + +static const char *const qup3_se1_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio15", +}; + +static const char *const qup3_se2_groups[] = { + "gpio12", "gpio13", "gpio14", "gpio15", +}; + +static const char *const qup3_se3_groups[] = { + "gpio16", "gpio17", "gpio18", "gpio19", +}; + +static const char *const qup3_se4_groups[] = { + "gpio20", "gpio21", "gpio22", "gpio23", +}; + +static const char *const qup3_se5_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", +}; + +static const char *const qup4_se0_groups[] = { + "gpio48", "gpio49", "gpio50", "gpio51", +}; + +static const char *const qup4_se1_groups[] = { + "gpio28", "gpio29", "gpio30", "gpio31", +}; + +static const char *const qup4_se2_groups[] = { + "gpio32", "gpio33", "gpio34", "gpio35", +}; + +static const char *const qup4_se3_groups[] = { + "gpio84", "gpio121", +}; + +static const char *const qup4_se4_groups[] = { + "gpio161", "gpio162", +}; + +static const char *const sd_write_protect_groups[] = { + "gpio85", +}; + +static const char *const sdc40_groups[] = { + "gpio80", +}; + +static const char *const sdc41_groups[] = { + "gpio147", +}; + +static const char *const sdc42_groups[] = { + "gpio81", +}; + +static const char *const sdc43_groups[] = { + "gpio82", +}; + +static const char *const sdc4_clk_groups[] = { + "gpio83", +}; + +static const char *const sdc4_cmd_groups[] = { + "gpio148", +}; + +static const char *const sys_throttle_groups[] = { + "gpio99", +}; + +static const char *const tb_trig_sdc2_groups[] = { + "gpio88", +}; + +static const char *const tb_trig_sdc4_groups[] = { + "gpio146", +}; + +static const char *const tmess_prng0_groups[] = { + "gpio85", +}; + +static const char *const tmess_prng1_groups[] = { + "gpio64", +}; + +static const char *const tmess_prng2_groups[] = { + "gpio65", +}; + +static const char *const tmess_prng3_groups[] = { + "gpio66", +}; + +static const char *const tsense_pwm1_groups[] = { + "gpio87", +}; + +static const char *const tsense_pwm2_groups[] = { + "gpio10", +}; + +static const char *const tsense_pwm3_groups[] = { + "gpio97", +}; + +static const char *const tsense_pwm4_groups[] = { + "gpio99", +}; + +static const char *const tsense_pwm5_groups[] = { + "gpio105", +}; + +static const char *const tsense_pwm6_groups[] = { + "gpio106", +}; + +static const char *const tsense_pwm7_groups[] = { + "gpio159", +}; + +static const char *const uim0_clk_groups[] = { + "gpio127", +}; + +static const char *const uim0_data_groups[] = { + "gpio126", +}; + +static const char *const uim0_present_groups[] = { + "gpio129", +}; + +static const char *const uim0_reset_groups[] = { + "gpio128", +}; + +static const char *const uim1_clk_groups[] = { + "gpio37", "gpio55", "gpio71", "gpio131", +}; + +static const char *const uim1_data_groups[] = { + "gpio36", "gpio54", "gpio70", "gpio130", +}; + +static const char *const uim1_present_groups[] = { + "gpio133", +}; + +static const char *const uim1_reset_groups[] = { + "gpio39", "gpio56", "gpio72", "gpio132", +}; + +static const char *const usb0_hs_groups[] = { + "gpio79", +}; + +static const char *const usb_phy_groups[] = { + "gpio59", "gpio60", +}; + +static const char *const vfr_0_groups[] = { + "gpio146", +}; + +static const char *const vfr_1_groups[] = { + "gpio151", +}; + +static const char *const vsense_trigger_mirnat_groups[] = { + "gpio59", +}; + +static const char *const wcn_sw_groups[] = { + "gpio19", +}; + +static const char *const wcn_sw_ctrl_groups[] = { + "gpio18", +}; + +static const struct pinfunction kaanapali_functions[] = { + MSM_GPIO_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(aoss_cti), + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_usb), + MSM_PIN_FUNCTION(audio_ext_mclk0), + MSM_PIN_FUNCTION(audio_ext_mclk1), + MSM_PIN_FUNCTION(audio_ref_clk), + MSM_PIN_FUNCTION(cam_asc_mclk2), + MSM_PIN_FUNCTION(cam_asc_mclk4), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(cci_async_in), + MSM_PIN_FUNCTION(cci_i2c_scl), + MSM_PIN_FUNCTION(cci_i2c_sda), + MSM_PIN_FUNCTION(cci_timer), + MSM_PIN_FUNCTION(cmu_rng), + MSM_PIN_FUNCTION(coex_uart1_rx), + MSM_PIN_FUNCTION(coex_uart1_tx), + MSM_PIN_FUNCTION(coex_uart2_rx), + MSM_PIN_FUNCTION(coex_uart2_tx), + MSM_PIN_FUNCTION(dbg_out_clk), + MSM_PIN_FUNCTION(ddr_bist_complete), + MSM_PIN_FUNCTION(ddr_bist_fail), + MSM_PIN_FUNCTION(ddr_bist_start), + MSM_PIN_FUNCTION(ddr_bist_stop), + MSM_PIN_FUNCTION(ddr_pxi0), + MSM_PIN_FUNCTION(ddr_pxi1), + MSM_PIN_FUNCTION(ddr_pxi2), + MSM_PIN_FUNCTION(ddr_pxi3), + MSM_PIN_FUNCTION(dp_hot), + MSM_PIN_FUNCTION(egpio), + MSM_PIN_FUNCTION(gcc_gp1), + MSM_PIN_FUNCTION(gcc_gp2), + MSM_PIN_FUNCTION(gcc_gp3), + MSM_PIN_FUNCTION(gnss_adc0), + MSM_PIN_FUNCTION(gnss_adc1), + MSM_PIN_FUNCTION(i2chub0_se0), + MSM_PIN_FUNCTION(i2chub0_se1), + MSM_PIN_FUNCTION(i2chub0_se2), + MSM_PIN_FUNCTION(i2chub0_se3), + MSM_PIN_FUNCTION(i2chub0_se4), + MSM_PIN_FUNCTION(i2s0_data0), + MSM_PIN_FUNCTION(i2s0_data1), + MSM_PIN_FUNCTION(i2s0_sck), + MSM_PIN_FUNCTION(i2s0_ws), + MSM_PIN_FUNCTION(i2s1_data0), + MSM_PIN_FUNCTION(i2s1_data1), + MSM_PIN_FUNCTION(i2s1_sck), + MSM_PIN_FUNCTION(i2s1_ws), + MSM_PIN_FUNCTION(ibi_i3c), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(mdp_esync0_out), + MSM_PIN_FUNCTION(mdp_esync1_out), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(mdp_vsync0_out), + MSM_PIN_FUNCTION(mdp_vsync1_out), + MSM_PIN_FUNCTION(mdp_vsync2_out), + MSM_PIN_FUNCTION(mdp_vsync3_out), + MSM_PIN_FUNCTION(mdp_vsync5_out), + MSM_PIN_FUNCTION(mdp_vsync_e), + MSM_PIN_FUNCTION(nav_gpio0), + MSM_PIN_FUNCTION(nav_gpio1), + MSM_PIN_FUNCTION(nav_gpio2), + MSM_PIN_FUNCTION(nav_gpio3), + MSM_PIN_FUNCTION(pcie0_clk_req_n), + MSM_PIN_FUNCTION(phase_flag), + MSM_PIN_FUNCTION(pll_bist_sync), + MSM_PIN_FUNCTION(pll_clk_aux), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qdss_gpio_traceclk), + MSM_PIN_FUNCTION(qdss_gpio_tracectl), + MSM_PIN_FUNCTION(qdss_gpio_tracedata), + MSM_PIN_FUNCTION(qlink_big_enable), + MSM_PIN_FUNCTION(qlink_big_request), + MSM_PIN_FUNCTION(qlink_little_enable), + MSM_PIN_FUNCTION(qlink_little_request), + MSM_PIN_FUNCTION(qlink_wmss), + MSM_PIN_FUNCTION(qspi0), + MSM_PIN_FUNCTION(qspi1), + MSM_PIN_FUNCTION(qspi2), + MSM_PIN_FUNCTION(qspi3), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qup1_se0), + MSM_PIN_FUNCTION(qup1_se1), + MSM_PIN_FUNCTION(qup1_se2), + MSM_PIN_FUNCTION(qup1_se3), + MSM_PIN_FUNCTION(qup1_se4), + MSM_PIN_FUNCTION(qup1_se5), + MSM_PIN_FUNCTION(qup1_se6), + MSM_PIN_FUNCTION(qup1_se7), + MSM_PIN_FUNCTION(qup2_se0), + MSM_PIN_FUNCTION(qup2_se1), + MSM_PIN_FUNCTION(qup2_se2), + MSM_PIN_FUNCTION(qup2_se3), + MSM_PIN_FUNCTION(qup2_se4), + MSM_PIN_FUNCTION(qup3_se0), + MSM_PIN_FUNCTION(qup3_se1), + MSM_PIN_FUNCTION(qup3_se2), + MSM_PIN_FUNCTION(qup3_se3), + MSM_PIN_FUNCTION(qup3_se4), + MSM_PIN_FUNCTION(qup3_se5), + MSM_PIN_FUNCTION(qup4_se0), + MSM_PIN_FUNCTION(qup4_se1), + MSM_PIN_FUNCTION(qup4_se2), + MSM_PIN_FUNCTION(qup4_se3), + MSM_PIN_FUNCTION(qup4_se4), + MSM_PIN_FUNCTION(sd_write_protect), + MSM_PIN_FUNCTION(sdc40), + MSM_PIN_FUNCTION(sdc41), + MSM_PIN_FUNCTION(sdc42), + MSM_PIN_FUNCTION(sdc43), + MSM_PIN_FUNCTION(sdc4_clk), + MSM_PIN_FUNCTION(sdc4_cmd), + MSM_PIN_FUNCTION(sys_throttle), + MSM_PIN_FUNCTION(tb_trig_sdc2), + MSM_PIN_FUNCTION(tb_trig_sdc4), + MSM_PIN_FUNCTION(tmess_prng0), + MSM_PIN_FUNCTION(tmess_prng1), + MSM_PIN_FUNCTION(tmess_prng2), + MSM_PIN_FUNCTION(tmess_prng3), + MSM_PIN_FUNCTION(tsense_pwm1), + MSM_PIN_FUNCTION(tsense_pwm2), + MSM_PIN_FUNCTION(tsense_pwm3), + MSM_PIN_FUNCTION(tsense_pwm4), + MSM_PIN_FUNCTION(tsense_pwm5), + MSM_PIN_FUNCTION(tsense_pwm6), + MSM_PIN_FUNCTION(tsense_pwm7), + MSM_PIN_FUNCTION(uim0_clk), + MSM_PIN_FUNCTION(uim0_data), + MSM_PIN_FUNCTION(uim0_present), + MSM_PIN_FUNCTION(uim0_reset), + MSM_PIN_FUNCTION(uim1_clk), + MSM_PIN_FUNCTION(uim1_data), + MSM_PIN_FUNCTION(uim1_present), + MSM_PIN_FUNCTION(uim1_reset), + MSM_PIN_FUNCTION(usb0_hs), + MSM_PIN_FUNCTION(usb_phy), + MSM_PIN_FUNCTION(vfr_0), + MSM_PIN_FUNCTION(vfr_1), + MSM_PIN_FUNCTION(vsense_trigger_mirnat), + MSM_PIN_FUNCTION(wcn_sw), + MSM_PIN_FUNCTION(wcn_sw_ctrl), +}; + +/* Every pin is maintained as a single group, and missing or non-existing pin + * would be maintained as dummy group to synchronize pin group index with + * pin descriptor registered with pinctrl core. + * Clients would not be able to request these dummy pin groups. + */ +static const struct msm_pingroup kaanapali_groups[] = { + [0] = PINGROUP(0, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [1] = PINGROUP(1, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [2] = PINGROUP(2, qup2_se0, _, _, _, _, _, _, _, _, _, egpio), + [3] = PINGROUP(3, qup2_se0, _, _, _, _, _, _, _, _, _, egpio), + [4] = PINGROUP(4, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [5] = PINGROUP(5, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [6] = PINGROUP(6, qup2_se1, _, _, _, _, _, _, _, _, _, egpio), + [7] = PINGROUP(7, qup2_se1, _, _, _, _, _, _, _, _, _, egpio), + [8] = PINGROUP(8, qup3_se1, ibi_i3c, _, _, _, _, _, _, _, _, _), + [9] = PINGROUP(9, qup3_se1, ibi_i3c, _, _, _, _, _, _, _, _, _), + [10] = PINGROUP(10, qup3_se1, cci_async_in, _, tsense_pwm2, _, _, _, _, _, _, _), + [11] = PINGROUP(11, qup3_se1, cci_async_in, _, _, _, _, _, _, _, _, _), + [12] = PINGROUP(12, qup3_se2, ibi_i3c, qup3_se1, _, _, _, _, _, _, _, _), + [13] = PINGROUP(13, qup3_se2, ibi_i3c, qup3_se1, _, _, _, _, _, _, _, _), + [14] = PINGROUP(14, qup3_se2, _, _, _, _, _, _, _, _, _, _), + [15] = PINGROUP(15, qup3_se2, cci_async_in, qup3_se1, _, _, _, _, _, _, _, _), + [16] = PINGROUP(16, qup3_se3, _, _, _, _, _, _, _, _, _, _), + [17] = PINGROUP(17, qup3_se3, _, _, _, _, _, _, _, _, _, _), + [18] = PINGROUP(18, wcn_sw_ctrl, qup3_se3, _, _, _, _, _, _, _, _, _), + [19] = PINGROUP(19, wcn_sw, qup3_se3, _, _, _, _, _, _, _, _, _), + [20] = PINGROUP(20, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [21] = PINGROUP(21, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [22] = PINGROUP(22, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [23] = PINGROUP(23, qup3_se4, _, _, _, _, _, _, _, _, _, _), + [24] = PINGROUP(24, qup3_se5, _, _, _, _, _, _, _, _, _, _), + [25] = PINGROUP(25, qup3_se5, _, _, _, _, _, _, _, _, _, _), + [26] = PINGROUP(26, qup3_se5, _, _, _, _, _, _, _, _, _, _), + [27] = PINGROUP(27, qup3_se5, qdss_cti, _, _, _, _, _, _, _, _, _), + [28] = PINGROUP(28, qup4_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [29] = PINGROUP(29, qup4_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [30] = PINGROUP(30, qup4_se1, _, _, _, _, _, _, _, _, _, _), + [31] = PINGROUP(31, qup4_se1, qdss_cti, _, _, _, _, _, _, _, _, _), + [32] = PINGROUP(32, qup4_se2, ibi_i3c, _, _, _, _, _, _, _, _, _), + [33] = PINGROUP(33, qup4_se2, ibi_i3c, _, _, _, _, _, _, _, _, _), + [34] = PINGROUP(34, qup4_se2, _, _, _, _, _, _, _, _, _, _), + [35] = PINGROUP(35, qup4_se2, _, _, _, _, _, _, _, _, _, _), + [36] = PINGROUP(36, qup1_se4, uim1_data, ibi_i3c, _, _, _, _, _, _, _, _), + [37] = PINGROUP(37, qup1_se4, uim1_clk, ibi_i3c, _, _, _, _, _, _, _, _), + [38] = PINGROUP(38, qup1_se4, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [39] = PINGROUP(39, qup1_se4, uim1_reset, qdss_gpio_tracedata, _, _, _, _, _, _, _, _), + [40] = PINGROUP(40, qup1_se2, cmu_rng, ddr_bist_fail, _, qdss_gpio_tracedata, gnss_adc0, + _, _, _, _, _), + [41] = PINGROUP(41, qup1_se2, cmu_rng, ddr_bist_start, _, qdss_gpio_tracedata, gnss_adc0, + _, _, _, _, _), + [42] = PINGROUP(42, qup1_se2, cmu_rng, dbg_out_clk, qdss_gpio_tracedata, gnss_adc1, _, _, + _, _, _, _), + [43] = PINGROUP(43, qup1_se2, cmu_rng, _, qdss_gpio_tracedata, ddr_pxi2, _, _, _, _, _, _), + [44] = PINGROUP(44, qup1_se3, ddr_bist_complete, ddr_pxi1, _, _, _, _, _, _, _, _), + [45] = PINGROUP(45, qup1_se3, ddr_bist_stop, ddr_pxi1, _, _, _, _, _, _, _, _), + [46] = PINGROUP(46, qup1_se3, ddr_pxi3, _, _, _, _, _, _, _, _, _), + [47] = PINGROUP(47, qup1_se3, dp_hot, _, _, _, _, _, _, _, _, _), + [48] = PINGROUP(48, qup4_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [49] = PINGROUP(49, qup4_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [50] = PINGROUP(50, qup4_se0, _, _, _, _, _, _, _, _, _, egpio), + [51] = PINGROUP(51, qup4_se0, _, _, _, _, _, _, _, _, _, egpio), + [52] = PINGROUP(52, qup1_se5, ddr_pxi2, _, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, qup1_se5, _, ddr_pxi3, _, _, _, _, _, _, _, _), + [54] = PINGROUP(54, qup1_se5, uim1_data, ddr_pxi0, _, _, _, _, _, _, _, _), + [55] = PINGROUP(55, qup1_se5, uim1_clk, ddr_pxi0, _, _, _, _, _, _, _, _), + [56] = PINGROUP(56, qup1_se6, uim1_reset, _, _, _, _, _, _, _, _, _), + [57] = PINGROUP(57, qup1_se6, _, _, _, _, _, _, _, _, _, _), + [58] = PINGROUP(58, qup1_se6, _, _, _, _, _, _, _, _, _, _), + [59] = PINGROUP(59, qup1_se6, usb_phy, vsense_trigger_mirnat, _, _, _, _, _, _, _, _), + [60] = PINGROUP(60, qup1_se7, usb_phy, ibi_i3c, _, _, _, _, _, _, _, _), + [61] = PINGROUP(61, qup1_se7, ibi_i3c, _, _, _, _, _, _, _, _, _), + [62] = PINGROUP(62, qup1_se7, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [63] = PINGROUP(63, qup1_se7, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [64] = PINGROUP(64, qup3_se0, _, prng_rosc1, tmess_prng1, _, _, _, _, _, _, _), + [65] = PINGROUP(65, qup3_se0, _, prng_rosc2, tmess_prng2, _, _, _, _, _, _, _), + [66] = PINGROUP(66, i2chub0_se0, prng_rosc3, tmess_prng3, _, _, _, _, _, _, _, _), + [67] = PINGROUP(67, i2chub0_se0, _, _, _, _, _, _, _, _, _, _), + [68] = PINGROUP(68, i2chub0_se2, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [69] = PINGROUP(69, i2chub0_se2, qdss_gpio_tracedata, _, _, _, _, _, _, _, _, _), + [70] = PINGROUP(70, i2chub0_se3, uim1_data, _, atest_usb, _, _, _, _, _, _, _), + [71] = PINGROUP(71, i2chub0_se3, uim1_clk, _, atest_usb, _, _, _, _, _, _, _), + [72] = PINGROUP(72, i2chub0_se4, uim1_reset, qdss_cti, _, atest_usb, _, _, _, _, _, _), + [73] = PINGROUP(73, i2chub0_se4, qdss_cti, jitter_bist, atest_usb, _, _, _, _, _, _, _), + [74] = PINGROUP(74, qup1_se1, aoss_cti, _, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, qup1_se1, aoss_cti, _, _, _, _, _, _, _, _, _), + [76] = PINGROUP(76, qup1_se1, aoss_cti, _, _, _, _, _, _, _, _, _), + [77] = PINGROUP(77, qup1_se1, aoss_cti, gnss_adc1, _, _, _, _, _, _, _, _), + [78] = PINGROUP(78, i2chub0_se1, _, _, _, _, _, _, _, _, _, _), + [79] = PINGROUP(79, i2chub0_se1, usb0_hs, _, _, _, _, _, _, _, _, _), + [80] = PINGROUP(80, qup1_se0, sdc40, qspi0, _, _, _, _, _, _, _, _), + [81] = PINGROUP(81, qup1_se0, sdc42, qspi2, _, _, _, _, _, _, _, _), + [82] = PINGROUP(82, qup1_se0, sdc43, qdss_cti, qspi3, _, _, _, _, _, _, _), + [83] = PINGROUP(83, qup1_se0, sdc4_clk, qdss_cti, qspi_clk, _, _, _, _, _, _, _), + [84] = PINGROUP(84, qup4_se3, _, _, _, _, _, _, _, _, _, _), + [85] = PINGROUP(85, sd_write_protect, prng_rosc0, tmess_prng0, _, _, _, _, _, _, _, _), + [86] = PINGROUP(86, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, gcc_gp2, _, _, _, _, _, _, + _), + [87] = PINGROUP(87, mdp_vsync, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync5_out, gcc_gp3, _, + tsense_pwm1, _, _, _, _), + [88] = PINGROUP(88, mdp_vsync_e, mdp_esync0_out, tb_trig_sdc2, _, _, _, _, _, _, _, _), + [89] = PINGROUP(89, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [90] = PINGROUP(90, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [91] = PINGROUP(91, cam_asc_mclk2, _, _, _, _, _, _, _, _, _, _), + [92] = PINGROUP(92, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [93] = PINGROUP(93, cam_asc_mclk4, _, _, _, _, _, _, _, _, _, _), + [94] = PINGROUP(94, cam_mclk, pll_clk_aux, _, _, _, _, _, _, _, _, _), + [95] = PINGROUP(95, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [96] = PINGROUP(96, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [97] = PINGROUP(97, mdp_vsync, tsense_pwm3, _, _, _, _, _, _, _, _, _), + [98] = PINGROUP(98, mdp_vsync, _, _, _, _, _, _, _, _, _, _), + [99] = PINGROUP(99, sys_throttle, tsense_pwm4, _, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, mdp_esync1_out, _, _, _, _, _, _, _, _, _, _), + [101] = PINGROUP(101, _, _, _, _, _, _, _, _, _, _, _), + [102] = PINGROUP(102, _, _, _, _, _, _, _, _, _, _, _), + [103] = PINGROUP(103, pcie0_clk_req_n, _, _, _, _, _, _, _, _, _, _), + [104] = PINGROUP(104, pll_bist_sync, _, _, _, _, _, _, _, _, _, _), + [105] = PINGROUP(105, cci_timer, tsense_pwm5, _, _, _, _, _, _, _, _, _), + [106] = PINGROUP(106, cci_timer, tsense_pwm6, _, _, _, _, _, _, _, _, _), + [107] = PINGROUP(107, cci_timer, cci_i2c_sda, _, _, _, _, _, _, _, _, _), + [108] = PINGROUP(108, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [109] = PINGROUP(109, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [110] = PINGROUP(110, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [111] = PINGROUP(111, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [112] = PINGROUP(112, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [113] = PINGROUP(113, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [114] = PINGROUP(114, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [116] = PINGROUP(116, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [117] = PINGROUP(117, i2s1_sck, qup2_se2, phase_flag, _, _, _, _, _, _, _, _), + [118] = PINGROUP(118, i2s1_data0, qup2_se2, phase_flag, _, _, _, _, _, _, _, _), + [119] = PINGROUP(119, i2s1_ws, qup2_se2, phase_flag, _, _, _, _, _, _, _, _), + [120] = PINGROUP(120, i2s1_data1, qup2_se2, audio_ext_mclk1, audio_ref_clk, _, _, _, _, _, + _, _), + [121] = PINGROUP(121, audio_ext_mclk0, qup4_se3, _, _, _, _, _, _, _, _, _), + [122] = PINGROUP(122, i2s0_sck, qup2_se3, _, _, _, _, _, _, _, _, _), + [123] = PINGROUP(123, i2s0_data0, qup2_se3, _, phase_flag, _, _, _, _, _, _, _), + [124] = PINGROUP(124, i2s0_data1, qup2_se3, _, phase_flag, _, _, _, _, _, _, _), + [125] = PINGROUP(125, i2s0_ws, qup2_se3, phase_flag, _, _, _, _, _, _, _, _), + [126] = PINGROUP(126, uim0_data, qdss_gpio_tracedata, atest_char, _, _, _, _, _, _, _, _), + [127] = PINGROUP(127, uim0_clk, qdss_gpio_tracectl, atest_char, _, _, _, _, _, _, _, _), + [128] = PINGROUP(128, uim0_reset, qdss_gpio_traceclk, atest_char, _, _, _, _, _, _, _, _), + [129] = PINGROUP(129, uim0_present, qdss_gpio_tracedata, atest_usb, atest_char, _, _, _, _, + _, _, _), + [130] = PINGROUP(130, uim1_data, qup1_se2, gcc_gp1, qdss_gpio_tracedata, _, _, _, _, _, _, + _), + [131] = PINGROUP(131, uim1_clk, qup1_se2, gcc_gp2, qdss_gpio_tracedata, _, _, _, _, _, _, + _), + [132] = PINGROUP(132, uim1_reset, qup1_se2, gcc_gp3, qdss_gpio_tracedata, _, _, _, _, _, _, + _), + [133] = PINGROUP(133, uim1_present, qdss_gpio_tracedata, atest_char, _, _, _, _, _, _, _, + _), + [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _, _, _), + [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _, _, _), + [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _, _, _), + [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _, _, _), + [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _, _, _), + [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _, _, _), + [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _, _, _), + [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _, _, _), + [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _, _, _), + [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _, _, _), + [144] = PINGROUP(144, coex_uart1_rx, cmu_rng, _, _, _, _, _, _, _, _, _), + [145] = PINGROUP(145, coex_uart1_tx, cmu_rng, _, _, _, _, _, _, _, _, _), + [146] = PINGROUP(146, _, vfr_0, coex_uart2_rx, cmu_rng, tb_trig_sdc4, qspi_cs, _, _, _, _, + _), + [147] = PINGROUP(147, _, coex_uart2_tx, cmu_rng, sdc41, qspi1, _, _, _, _, _, _), + [148] = PINGROUP(148, nav_gpio2, _, sdc4_cmd, qspi_cs, _, _, _, _, _, _, _), + [149] = PINGROUP(149, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [150] = PINGROUP(150, nav_gpio0, nav_gpio3, _, _, _, _, _, _, _, _, _), + [151] = PINGROUP(151, nav_gpio1, vfr_1, _, _, _, _, _, _, _, _, _), + [152] = PINGROUP(152, qlink_little_request, _, _, _, _, _, _, _, _, _, _), + [153] = PINGROUP(153, qlink_little_enable, _, _, _, _, _, _, _, _, _, _), + [154] = PINGROUP(154, qlink_wmss, _, _, _, _, _, _, _, _, _, _), + [155] = PINGROUP(155, qlink_big_request, qdss_cti, _, _, _, _, _, _, _, _, _), + [156] = PINGROUP(156, qlink_big_enable, _, _, _, _, _, _, _, _, _, _), + [157] = PINGROUP(157, _, _, _, _, _, _, _, _, _, _, _), + [158] = PINGROUP(158, qdss_cti, gcc_gp1, _, _, _, _, _, _, _, _, _), + [159] = PINGROUP(159, cci_timer, tsense_pwm7, _, _, _, _, _, _, _, _, _), + [160] = PINGROUP(160, cci_timer, cci_i2c_scl, _, _, _, _, _, _, _, _, _), + [161] = PINGROUP(161, qup4_se4, _, _, _, _, _, _, _, _, _, _), + [162] = PINGROUP(162, qup4_se4, _, _, _, _, _, _, _, _, _, _), + [163] = PINGROUP(163, _, _, _, _, _, _, _, _, _, _, egpio), + [164] = PINGROUP(164, _, _, _, _, _, _, _, _, _, _, egpio), + [165] = PINGROUP(165, _, _, _, _, _, _, _, _, _, _, egpio), + [166] = PINGROUP(166, _, _, _, _, _, _, _, _, _, _, egpio), + [167] = PINGROUP(167, _, _, _, _, _, _, _, _, _, _, egpio), + [168] = PINGROUP(168, _, _, _, _, _, _, _, _, _, _, egpio), + [169] = PINGROUP(169, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [170] = PINGROUP(170, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [171] = PINGROUP(171, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [172] = PINGROUP(172, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [173] = PINGROUP(173, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [174] = PINGROUP(174, _, _, _, _, _, _, _, _, _, _, egpio), + [175] = PINGROUP(175, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [176] = PINGROUP(176, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [177] = PINGROUP(177, _, _, _, _, _, _, _, _, _, _, egpio), + [178] = PINGROUP(178, _, _, _, _, _, _, _, _, _, _, egpio), + [179] = PINGROUP(179, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [180] = PINGROUP(180, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [181] = PINGROUP(181, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [182] = PINGROUP(182, _, _, _, _, _, _, _, _, _, _, egpio), + [183] = PINGROUP(183, _, _, _, _, _, _, _, _, _, _, egpio), + [184] = PINGROUP(184, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [185] = PINGROUP(185, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [186] = PINGROUP(186, _, _, _, _, _, _, _, _, _, _, egpio), + [187] = PINGROUP(187, _, _, _, _, _, _, _, _, _, _, egpio), + [188] = PINGROUP(188, _, _, _, _, _, _, _, _, _, _, egpio), + [189] = PINGROUP(189, _, _, _, _, _, _, _, _, _, _, egpio), + [190] = PINGROUP(190, _, _, _, _, _, _, _, _, _, _, egpio), + [191] = PINGROUP(191, _, _, _, _, _, _, _, _, _, _, egpio), + [192] = PINGROUP(192, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [193] = PINGROUP(193, _, _, _, _, _, _, _, _, _, _, egpio), + [194] = PINGROUP(194, _, _, _, _, _, _, _, _, _, _, egpio), + [195] = PINGROUP(195, _, _, _, _, _, _, _, _, _, _, egpio), + [196] = PINGROUP(196, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [197] = PINGROUP(197, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [198] = PINGROUP(198, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [199] = PINGROUP(199, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [200] = PINGROUP(200, _, _, _, _, _, _, _, _, _, _, egpio), + [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _, _, egpio), + [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _, _, egpio), + [203] = PINGROUP(203, _, _, _, _, _, _, _, _, _, _, egpio), + [204] = PINGROUP(204, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [205] = PINGROUP(205, _, _, _, _, _, _, _, _, _, _, egpio), + [206] = PINGROUP(206, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [207] = PINGROUP(207, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [208] = PINGROUP(208, qup2_se4, _, phase_flag, _, _, _, _, _, _, _, egpio), + [209] = PINGROUP(209, qup2_se4, _, _, _, _, _, _, _, _, _, egpio), + [210] = PINGROUP(210, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [211] = PINGROUP(211, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [212] = PINGROUP(212, _, _, _, _, _, _, _, _, _, _, egpio), + [213] = PINGROUP(213, _, _, _, _, _, _, _, _, _, _, egpio), + [214] = PINGROUP(214, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [215] = PINGROUP(215, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [216] = PINGROUP(216, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [217] = UFS_RESET(ufs_reset, 0xe8004, 0xe9000), + [218] = SDC_QDSD_PINGROUP(sdc2_clk, 0xdd000, 14, 6), + [219] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xdd000, 11, 3), + [220] = SDC_QDSD_PINGROUP(sdc2_data, 0xdd000, 9, 0), +}; + +static const struct msm_gpio_wakeirq_map kaanapali_pdc_map[] = { + { 0, 89 }, { 3, 97 }, { 4, 90 }, { 7, 91 }, { 8, 92 }, { 11, 93 }, + { 12, 101 }, { 15, 115 }, { 17, 125 }, { 18, 127 }, { 19, 96 }, { 23, 99 }, + { 24, 100 }, { 27, 102 }, { 28, 103 }, { 31, 111 }, { 32, 109 }, { 35, 85 }, + { 36, 110 }, { 39, 112 }, { 43, 113 }, { 47, 138 }, { 48, 114 }, { 51, 98 }, + { 55, 88 }, { 57, 120 }, { 59, 121 }, { 60, 122 }, { 63, 108 }, { 64, 94 }, + { 65, 107 }, { 67, 116 }, { 68, 129 }, { 69, 130 }, { 75, 135 }, { 77, 123 }, + { 78, 119 }, { 79, 131 }, { 80, 139 }, { 81, 132 }, { 84, 118 }, { 85, 133 }, + { 86, 140 }, { 87, 141 }, { 88, 142 }, { 95, 143 }, { 96, 144 }, { 97, 117 }, + { 98, 134 }, { 99, 95 }, { 101, 145 }, { 102, 146 }, { 103, 147 }, { 104, 148 }, + { 120, 149 }, { 125, 150 }, { 129, 137 }, { 133, 84 }, { 144, 151 }, { 146, 152 }, + { 151, 153 }, { 152, 154 }, { 155, 106 }, { 158, 104 }, { 162, 126 }, { 164, 155 }, + { 167, 156 }, { 169, 157 }, { 170, 158 }, { 172, 159 }, { 174, 160 }, { 175, 161 }, + { 179, 162 }, { 180, 163 }, { 183, 164 }, { 186, 165 }, { 188, 128 }, { 189, 166 }, + { 190, 105 }, { 191, 167 }, { 194, 168 }, { 195, 169 }, { 196, 170 }, { 197, 171 }, + { 199, 136 }, { 200, 86 }, { 201, 172 }, { 202, 173 }, { 203, 174 }, { 205, 124 }, + { 209, 175 }, { 213, 87 }, { 216, 176 }, +}; + +static const struct msm_pinctrl_soc_data kaanapali_tlmm = { + .pins = kaanapali_pins, + .npins = ARRAY_SIZE(kaanapali_pins), + .functions = kaanapali_functions, + .nfunctions = ARRAY_SIZE(kaanapali_functions), + .groups = kaanapali_groups, + .ngroups = ARRAY_SIZE(kaanapali_groups), + .ngpios = 218, + .wakeirq_map = kaanapali_pdc_map, + .nwakeirq_map = ARRAY_SIZE(kaanapali_pdc_map), + .egpio_func = 11, +}; + +static int kaanapali_tlmm_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &kaanapali_tlmm); +} + +static const struct of_device_id kaanapali_tlmm_of_match[] = { + { .compatible = "qcom,kaanapali-tlmm",}, + {}, +}; + +static struct platform_driver kaanapali_tlmm_driver = { + .driver = { + .name = "kaanapali-tlmm", + .of_match_table = kaanapali_tlmm_of_match, + }, + .probe = kaanapali_tlmm_probe, +}; + +static int __init kaanapali_tlmm_init(void) +{ + return platform_driver_register(&kaanapali_tlmm_driver); +} +arch_initcall(kaanapali_tlmm_init); + +static void __exit kaanapali_tlmm_exit(void) +{ + platform_driver_unregister(&kaanapali_tlmm_driver); +} +module_exit(kaanapali_tlmm_exit); + +MODULE_DESCRIPTION("QTI Kaanapali TLMM driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, kaanapali_tlmm_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 485b68cc93f8..83f940fe30b2 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -42,6 +42,8 @@ #define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11 #define PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2 0x12 #define PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3 0x13 +#define PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2_CLK 0x14 +#define PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3_CLK 0x15 #define PMIC_MPP_REG_RT_STS 0x10 #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 @@ -852,11 +854,13 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state, pad->lv_mv_type = true; break; case PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2: + case PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2_CLK: pad->num_sources = 2; pad->have_buffer = true; pad->lv_mv_type = true; break; case PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3: + case PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3_CLK: pad->num_sources = 3; pad->have_buffer = true; pad->lv_mv_type = true; @@ -1239,7 +1243,11 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8998-gpio", .data = (void *) 26 }, { .compatible = "qcom,pma8084-gpio", .data = (void *) 22 }, { .compatible = "qcom,pmc8380-gpio", .data = (void *) 10 }, + { .compatible = "qcom,pmcx0102-gpio", .data = (void *)14 }, { .compatible = "qcom,pmd8028-gpio", .data = (void *) 4 }, + { .compatible = "qcom,pmh0101-gpio", .data = (void *)18 }, + { .compatible = "qcom,pmh0104-gpio", .data = (void *)8 }, + { .compatible = "qcom,pmh0110-gpio", .data = (void *)14 }, { .compatible = "qcom,pmi632-gpio", .data = (void *) 8 }, { .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 }, { .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 }, @@ -1248,6 +1256,7 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pmiv0104-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 }, { .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 }, + { .compatible = "qcom,pmk8850-gpio", .data = (void *)8 }, { .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmm8654au-gpio", .data = (void *) 12 }, /* pmp8074 has 12 GPIOs with holes on 1 and 12 */ diff --git a/drivers/pinctrl/renesas/pfc-emev2.c b/drivers/pinctrl/renesas/pfc-emev2.c index 86d18b03668e..eee23ac87076 100644 --- a/drivers/pinctrl/renesas/pfc-emev2.c +++ b/drivers/pinctrl/renesas/pfc-emev2.c @@ -666,7 +666,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_NOFN(UART_1_0_PORT158, UART2_TX, SEL_UART_1_0_01), }; - #define EMEV_MUX_PIN(name, pin, mark) \ static const unsigned int name##_pins[] = { pin }; \ static const unsigned int name##_mux[] = { mark##_MARK } diff --git a/drivers/pinctrl/renesas/pfc-r8a73a4.c b/drivers/pinctrl/renesas/pfc-r8a73a4.c index be0a4914eab3..1b00765192f5 100644 --- a/drivers/pinctrl/renesas/pfc-r8a73a4.c +++ b/drivers/pinctrl/renesas/pfc-r8a73a4.c @@ -85,7 +85,6 @@ /* Port320 - Port329 */ \ PORT_10(320, fn, pfx##32, sfx) - enum { PINMUX_RESERVED = 0, @@ -227,7 +226,6 @@ enum { PINMUX_MARK_BEGIN, - #define F1(a) a##_MARK #define F2(a) a##_MARK #define F3(a) a##_MARK diff --git a/drivers/pinctrl/renesas/pfc-r8a7778.c b/drivers/pinctrl/renesas/pfc-r8a7778.c index db92d6d91d8e..4611e864ba69 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7778.c +++ b/drivers/pinctrl/renesas/pfc-r8a7778.c @@ -1994,7 +1994,6 @@ static const char * const scif5_groups[] = { "scif5_data_b", }; - static const char * const sdhi0_groups[] = { "sdhi0_cd", "sdhi0_ctrl", diff --git a/drivers/pinctrl/renesas/pfc-r8a77951.c b/drivers/pinctrl/renesas/pfc-r8a77951.c index a1d74f61fd8c..4b04cb9134b6 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77951.c +++ b/drivers/pinctrl/renesas/pfc-r8a77951.c @@ -249,7 +249,6 @@ #define GPSR7_1 FM(AVS2) #define GPSR7_0 FM(AVS1) - /* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ #define IP0_3_0 FM(AVB_MDC) F_(0, 0) FM(MSIOF2_SS2_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0_7_4 FM(AVB_MAGIC) F_(0, 0) FM(MSIOF2_SS1_C) FM(SCK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) diff --git a/drivers/pinctrl/renesas/pfc-r8a7796.c b/drivers/pinctrl/renesas/pfc-r8a7796.c index 807834f319f0..aead3b1173c9 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7796.c +++ b/drivers/pinctrl/renesas/pfc-r8a7796.c @@ -254,7 +254,6 @@ #define GPSR7_1 FM(AVS2) #define GPSR7_0 FM(AVS1) - /* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ #define IP0_3_0 FM(AVB_MDC) F_(0, 0) FM(MSIOF2_SS2_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0_7_4 FM(AVB_MAGIC) F_(0, 0) FM(MSIOF2_SS1_C) FM(SCK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) diff --git a/drivers/pinctrl/renesas/pfc-r8a77965.c b/drivers/pinctrl/renesas/pfc-r8a77965.c index e7c88a5d983f..22640cfe9e32 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77965.c +++ b/drivers/pinctrl/renesas/pfc-r8a77965.c @@ -254,7 +254,6 @@ #define GPSR7_1 FM(AVS2) #define GPSR7_0 FM(AVS1) - /* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ #define IP0_3_0 FM(AVB_MDC) F_(0, 0) FM(MSIOF2_SS2_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0_7_4 FM(AVB_MAGIC) F_(0, 0) FM(MSIOF2_SS1_C) FM(SCK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) diff --git a/drivers/pinctrl/renesas/pfc-r8a77970.c b/drivers/pinctrl/renesas/pfc-r8a77970.c index e1b3e3b38ec3..972b14ab2359 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77970.c +++ b/drivers/pinctrl/renesas/pfc-r8a77970.c @@ -159,7 +159,6 @@ #define GPSR5_1 FM(QSPI0_MOSI_IO0) #define GPSR5_0 FM(QSPI0_SPCLK) - /* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 - F */ #define IP0_3_0 FM(DU_DR2) FM(HSCK0) F_(0, 0) FM(A0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0_7_4 FM(DU_DR3) FM(HRTS0_N) F_(0, 0) FM(A1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) diff --git a/drivers/pinctrl/renesas/pfc-r8a77980.c b/drivers/pinctrl/renesas/pfc-r8a77980.c index 877134d78c7e..53b44b24bfc6 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77980.c +++ b/drivers/pinctrl/renesas/pfc-r8a77980.c @@ -193,7 +193,6 @@ #define GPSR5_1 FM(QSPI0_MOSI_IO0) #define GPSR5_0 FM(QSPI0_SPCLK) - /* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 - F */ #define IP0_3_0 FM(DU_DR2) FM(SCK4) FM(GETHER_RMII_CRS_DV) FM(A0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0_7_4 FM(DU_DR3) FM(RX4) FM(GETHER_RMII_RX_ER) FM(A1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) diff --git a/drivers/pinctrl/renesas/pfc-r8a77995.c b/drivers/pinctrl/renesas/pfc-r8a77995.c index 298e7a07e493..b35c62f9a061 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77995.c +++ b/drivers/pinctrl/renesas/pfc-r8a77995.c @@ -427,7 +427,6 @@ FM(IP12_31_28) IP12_31_28 \ #define MOD_SEL1_27 FM(SEL_SCIF0_0) FM(SEL_SCIF0_1) #define MOD_SEL1_26 FM(SEL_SSIF4_0) FM(SEL_SSIF4_1) - #define PINMUX_MOD_SELS \ \ MOD_SEL1_31 \ @@ -2869,7 +2868,6 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { { /* sentinel */ } }; - static int r8a77995_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) { switch (pin) { diff --git a/drivers/pinctrl/renesas/pfc-r8a779f0.c b/drivers/pinctrl/renesas/pfc-r8a779f0.c index 16e722a4d18f..46ca28fb2d51 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779f0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779f0.c @@ -652,7 +652,6 @@ static const unsigned int i2c5_mux[] = { SDA5_MARK, SCL5_MARK, }; - /* - INTC-EX ---------------------------------------------------------------- */ static const unsigned int intc_ex_irq0_pins[] = { /* IRQ0 */ diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c index 218c5eff9b67..1c8abd68583a 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779g0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c @@ -352,7 +352,7 @@ #define IP1SR2_3_0 FM(TPU0TO0_A) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -471,55 +471,55 @@ #define IP0SR6_7_4 FM(AVB1_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR6_11_8 FM(AVB1_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR6_15_12 FM(AVB1_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_19_16 FM(AVB1_LINK) FM(AVB1_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) FM(AVB1_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_27_24 FM(AVB1_TXC) FM(AVB1_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_31_28 FM(AVB1_TX_CTL) FM(AVB1_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_19_16 FM(AVB1_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_27_24 FM(AVB1_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_31_28 FM(AVB1_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR6_3_0 FM(AVB1_RXC) FM(AVB1_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_7_4 FM(AVB1_RX_CTL) FM(AVB1_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) FM(AVB1_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) FM(AVB1_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_19_16 FM(AVB1_TD1) FM(AVB1_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_23_20 FM(AVB1_TD0) FM(AVB1_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_27_24 FM(AVB1_RD1) FM(AVB1_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_31_28 FM(AVB1_RD0) FM(AVB1_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_3_0 FM(AVB1_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_7_4 FM(AVB1_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_19_16 FM(AVB1_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_23_20 FM(AVB1_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_27_24 FM(AVB1_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_31_28 FM(AVB1_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR6_3_0 FM(AVB1_TD2) FM(AVB1_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_7_4 FM(AVB1_RD2) FM(AVB1_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_11_8 FM(AVB1_TD3) FM(AVB1_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_15_12 FM(AVB1_RD3) FM(AVB1_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_3_0 FM(AVB1_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_7_4 FM(AVB1_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_11_8 FM(AVB1_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_15_12 FM(AVB1_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2SR6_19_16 FM(AVB1_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR7 */ /* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_15_12 FM(AVB0_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_19_16 FM(AVB0_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_27_24 FM(AVB0_TD2) FM(AVB0_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_31_28 FM(AVB0_TD1) FM(AVB0_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_27_24 FM(AVB0_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_31_28 FM(AVB0_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR7_3_0 FM(AVB0_RD3) FM(AVB0_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_3_0 FM(AVB0_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_7_4 FM(AVB0_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_11_8 FM(AVB0_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_15_12 FM(AVB0_TD0) FM(AVB0_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_19_16 FM(AVB0_RD2) FM(AVB0_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_15_12 FM(AVB0_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_19_16 FM(AVB0_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_23_20 FM(AVB0_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_27_24 FM(AVB0_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_31_28 FM(AVB0_TXC) FM(AVB0_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_31_28 FM(AVB0_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR7_3_0 FM(AVB0_TX_CTL) FM(AVB0_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_7_4 FM(AVB0_RD1) FM(AVB0_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_11_8 FM(AVB0_RD0) FM(AVB0_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_15_12 FM(AVB0_RXC) FM(AVB0_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_19_16 FM(AVB0_RX_CTL) FM(AVB0_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_3_0 FM(AVB0_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_7_4 FM(AVB0_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_11_8 FM(AVB0_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_15_12 FM(AVB0_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_19_16 FM(AVB0_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR8 */ /* IP0SR8 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -925,7 +925,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), - PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), @@ -1076,118 +1075,85 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP0SR6_15_12, AVB1_PHY_INT), PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_LINK), - PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_MII_TX_ER), PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_AVTP_MATCH), - PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_MII_RX_ER), PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_TXC), - PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_MII_TXC), PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_TX_CTL), - PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_MII_TX_EN), /* IP1SR6 */ PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_RXC), - PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_MII_RXC), PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_RX_CTL), - PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_MII_RX_DV), PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_AVTP_PPS), - PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_MII_COL), PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_AVTP_CAPTURE), - PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_MII_CRS), PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_TD1), - PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_MII_TD1), PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_TD0), - PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_MII_TD0), PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_RD1), - PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_MII_RD1), PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_RD0), - PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_MII_RD0), /* IP2SR6 */ PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_TD2), - PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_MII_TD2), PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_RD2), - PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_MII_RD2), PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_TD3), - PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_MII_TD3), PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_RD3), - PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_MII_RD3), PINMUX_IPSR_GPSR(IP2SR6_19_16, AVB1_TXCREFCLK), /* IP0SR7 */ PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_AVTP_PPS), - PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_MII_COL), PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_AVTP_CAPTURE), - PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_MII_CRS), PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH), - PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER), - PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3), - PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3), PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_LINK), - PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_MII_TX_ER), PINMUX_IPSR_GPSR(IP0SR7_23_20, AVB0_PHY_INT), PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_TD2), - PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_MII_TD2), PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_TD1), - PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_MII_TD1), /* IP1SR7 */ PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_RD3), - PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_MII_RD3), PINMUX_IPSR_GPSR(IP1SR7_7_4, AVB0_TXCREFCLK), PINMUX_IPSR_GPSR(IP1SR7_11_8, AVB0_MAGIC), PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_TD0), - PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_MII_TD0), PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_RD2), - PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_MII_RD2), PINMUX_IPSR_GPSR(IP1SR7_23_20, AVB0_MDC), PINMUX_IPSR_GPSR(IP1SR7_27_24, AVB0_MDIO), PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_TXC), - PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_MII_TXC), /* IP2SR7 */ PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_TX_CTL), - PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_MII_TX_EN), PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_RD1), - PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_MII_RD1), PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_RD0), - PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_MII_RD0), PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_RXC), - PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_MII_RXC), PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_RX_CTL), - PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_MII_RX_DV), /* IP0SR8 */ PINMUX_IPSR_MSEL(IP0SR8_3_0, SCL0, SEL_SCL0_0), diff --git a/drivers/pinctrl/renesas/pfc-r8a779h0.c b/drivers/pinctrl/renesas/pfc-r8a779h0.c index 48b1eef250d9..ec0fc1bf7a90 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779h0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779h0.c @@ -259,7 +259,6 @@ #define GPSR7_1 F_(AVB0_AVTP_CAPTURE, IP0SR7_7_4) #define GPSR7_0 F_(AVB0_AVTP_PPS, IP0SR7_3_0) - /* SR0 */ /* IP0SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ #define IP0SR0_3_0 F_(0, 0) FM(ERROROUTC_N_B) FM(TCLK2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -340,7 +339,7 @@ #define IP1SR2_3_0 FM(TPU0TO0_A) F_(0, 0) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -479,7 +478,7 @@ /* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ #define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -866,7 +865,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), - PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), @@ -1124,7 +1122,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH), PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER), - PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3), diff --git a/drivers/pinctrl/renesas/pfc-sh7723.c b/drivers/pinctrl/renesas/pfc-sh7723.c index c1abdec9bf1d..bdf555e63c2e 100644 --- a/drivers/pinctrl/renesas/pfc-sh7723.c +++ b/drivers/pinctrl/renesas/pfc-sh7723.c @@ -182,7 +182,6 @@ enum { PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN, PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN, - PSA15_PSA14_FN1, PSA15_PSA14_FN2, PSA13_PSA12_FN1, PSA13_PSA12_FN2, PSA11_PSA10_FN1, PSA11_PSA10_FN2, diff --git a/drivers/pinctrl/renesas/pfc-sh7724.c b/drivers/pinctrl/renesas/pfc-sh7724.c index 5148a3460cc6..4e8c1fae7be6 100644 --- a/drivers/pinctrl/renesas/pfc-sh7724.c +++ b/drivers/pinctrl/renesas/pfc-sh7724.c @@ -210,7 +210,6 @@ enum { PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN, PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN, - PSA15_0, PSA15_1, PSA14_0, PSA14_1, PSA13_0, PSA13_1, diff --git a/drivers/pinctrl/renesas/pfc-sh7734.c b/drivers/pinctrl/renesas/pfc-sh7734.c index a0a5d8b94086..df2de853df93 100644 --- a/drivers/pinctrl/renesas/pfc-sh7734.c +++ b/drivers/pinctrl/renesas/pfc-sh7734.c @@ -664,7 +664,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP0_31_30, LCD_DATA15_A, SEL_LCDC_0), PINMUX_IPSR_MSEL(IP0_31_30, TIOC3D_C, SEL_MTU2_CH3_1), - /* IPSR1 */ PINMUX_IPSR_GPSR(IP1_1_0, A16), PINMUX_IPSR_GPSR(IP1_1_0, ST0_PWM), diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c index f24e5915cbe4..3cfa4c8be80e 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza1.c +++ b/drivers/pinctrl/renesas/pinctrl-rza1.c @@ -526,7 +526,6 @@ static inline int rza1_pinmux_get_swio(unsigned int port, const struct rza1_swio_pin *swio_pin; unsigned int i; - for (i = 0; i < table->npins; ++i) { swio_pin = &table->pins[i]; if (swio_pin->port == port && swio_pin->pin == pin && @@ -669,7 +668,7 @@ static inline int rza1_pin_get(struct rza1_port *port, unsigned int pin) * @mux_conf: pin multiplexing descriptor */ static int rza1_pin_mux_single(struct rza1_pinctrl *rza1_pctl, - struct rza1_mux_conf *mux_conf) + const struct rza1_mux_conf *mux_conf) { struct rza1_port *port = &rza1_pctl->ports[mux_conf->port]; unsigned int pin = mux_conf->pin; @@ -1119,7 +1118,7 @@ static int rza1_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, unsigned int group) { struct rza1_pinctrl *rza1_pctl = pinctrl_dev_get_drvdata(pctldev); - struct rza1_mux_conf *mux_confs; + const struct rza1_mux_conf *mux_confs; const struct function_desc *func; struct group_desc *grp; int i; @@ -1132,7 +1131,7 @@ static int rza1_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, if (!func) return -EINVAL; - mux_confs = (struct rza1_mux_conf *)func->data; + mux_confs = (const struct rza1_mux_conf *)func->data; for (i = 0; i < grp->grp.npins; ++i) { int ret; diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index f524af6f586f..863e779dda02 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -359,7 +359,7 @@ struct rzg2l_pinctrl { spinlock_t bitmap_lock; /* protect tint_slot bitmap */ unsigned int hwirq[RZG2L_TINT_MAX_INTERRUPT]; - spinlock_t lock; /* lock read/write registers */ + raw_spinlock_t lock; /* lock read/write registers */ struct mutex mutex; /* serialize adding groups and functions */ struct rzg2l_pinctrl_pin_settings *settings; @@ -541,9 +541,16 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, u8 pin, u8 off, u8 func) { unsigned long flags; - u32 reg; + u32 reg, pfc; - spin_lock_irqsave(&pctrl->lock, flags); + /* Switching to GPIO is not required if reset value is same as func */ + raw_spin_lock_irqsave(&pctrl->lock, flags); + reg = readb(pctrl->base + PMC(off)); + pfc = readl(pctrl->base + PFC(off)); + if ((reg & BIT(pin)) && (((pfc >> (pin * 4)) & PFC_MASK) == func)) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return; + } /* Set pin to 'Non-use (Hi-Z input protection)' */ reg = readw(pctrl->base + PM(off)); @@ -557,9 +564,8 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, writeb(reg & ~BIT(pin), pctrl->base + PMC(off)); /* Select Pin function mode with PFC register */ - reg = readl(pctrl->base + PFC(off)); - reg &= ~(PFC_MASK << (pin * 4)); - writel(reg | (func << (pin * 4)), pctrl->base + PFC(off)); + pfc &= ~(PFC_MASK << (pin * 4)); + writel(pfc | (func << (pin * 4)), pctrl->base + PFC(off)); /* Switch to Peripheral pin function with PMC register */ reg = readb(pctrl->base + PMC(off)); @@ -567,8 +573,8 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); - spin_unlock_irqrestore(&pctrl->lock, flags); -}; + raw_spin_unlock_irqrestore(&pctrl->lock, flags); +} static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, @@ -608,7 +614,7 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev, } return 0; -}; +} static int rzg2l_map_add_config(struct pinctrl_map *map, const char *group_or_pin, @@ -882,10 +888,10 @@ static void rzg2l_rmw_pin_config(struct rzg2l_pinctrl *pctrl, u32 offset, addr += 4; } - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg = readl(addr) & ~(mask << (bit * 8)); writel(reg | (val << (bit * 8)), addr); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs, u32 caps) @@ -1106,13 +1112,37 @@ static int rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) return !(readb(pctrl->base + pctrl->data->hwcfg->regs.oen) & BIT(bit)); } -static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) +/** + * rzg2l_oen_write_with_pwpr - Write to OEN register with PWPR protection + * @pctrl: pinctrl driver data + * @val: value to write to OEN register + * + * Writes to the OEN register, handling PWPR write protection if required + * by the hardware configuration. Must be called with pctrl->lock held. + */ +static void rzg2l_oen_write_with_pwpr(struct rzg2l_pinctrl *pctrl, u8 val) { const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs; u16 oen_offset = pctrl->data->hwcfg->regs.oen; + u8 pwpr; + + if (pctrl->data->hwcfg->oen_pwpr_lock) { + pwpr = readb(pctrl->base + regs->pwpr); + writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); + } + + writeb(val, pctrl->base + oen_offset); + + if (pctrl->data->hwcfg->oen_pwpr_lock) + writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); +} + +static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) +{ + u16 oen_offset = pctrl->data->hwcfg->regs.oen; unsigned long flags; - u8 val, pwpr; int bit; + u8 val; if (!pctrl->data->pin_to_oen_bit) return -EOPNOTSUPP; @@ -1121,20 +1151,15 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe if (bit < 0) return -EINVAL; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); val = readb(pctrl->base + oen_offset); if (oen) val &= ~BIT(bit); else val |= BIT(bit); - if (pctrl->data->hwcfg->oen_pwpr_lock) { - pwpr = readb(pctrl->base + regs->pwpr); - writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); - } - writeb(val, pctrl->base + oen_offset); - if (pctrl->data->hwcfg->oen_pwpr_lock) - writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); - spin_unlock_irqrestore(&pctrl->lock, flags); + + rzg2l_oen_write_with_pwpr(pctrl, val); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1413,7 +1438,7 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, *config = pinconf_to_config_packed(param, arg); return 0; -}; +} static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, unsigned int _pin, @@ -1613,7 +1638,7 @@ static int rzg2l_pinctrl_pinconf_group_set(struct pinctrl_dev *pctldev, } return 0; -}; +} static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, unsigned int group, @@ -1640,7 +1665,7 @@ static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, } return 0; -}; +} static const struct pinctrl_ops rzg2l_pinctrl_pctlops = { .get_groups_count = pinctrl_generic_get_group_count, @@ -1687,14 +1712,14 @@ static int rzg2l_gpio_request(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); /* Select GPIO mode in PMC Register */ reg8 = readb(pctrl->base + PMC(off)); reg8 &= ~BIT(bit); pctrl->data->pmc_writeb(pctrl, reg8, PMC(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1709,7 +1734,7 @@ static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 offset, unsigned long flags; u16 reg16; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg16 = readw(pctrl->base + PM(off)); reg16 &= ~(PM_MASK << (bit * 2)); @@ -1717,7 +1742,7 @@ static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 offset, reg16 |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2); writew(reg16, pctrl->base + PM(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) @@ -1761,7 +1786,7 @@ static int rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset, unsigned long flags; u8 reg8; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg8 = readb(pctrl->base + P(off)); @@ -1770,7 +1795,7 @@ static int rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset, else writeb(reg8 & ~BIT(bit), pctrl->base + P(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -2429,14 +2454,13 @@ static int rzg2l_gpio_get_gpioint(unsigned int virq, struct rzg2l_pinctrl *pctrl return gpioint; } -static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, - unsigned int hwirq, bool enable) +static void __rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, + unsigned int hwirq, bool enable) { const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[hwirq]; u64 *pin_data = pin_desc->drv_data; u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data); u8 bit = RZG2L_PIN_ID_TO_PIN(hwirq); - unsigned long flags; void __iomem *addr; addr = pctrl->base + ISEL(off); @@ -2445,12 +2469,20 @@ static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, addr += 4; } - spin_lock_irqsave(&pctrl->lock, flags); if (enable) writel(readl(addr) | BIT(bit * 8), addr); else writel(readl(addr) & ~BIT(bit * 8), addr); - spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, + unsigned int hwirq, bool enable) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + __rzg2l_gpio_irq_endisable(pctrl, hwirq, enable); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void rzg2l_gpio_irq_disable(struct irq_data *d) @@ -2462,23 +2494,23 @@ static void rzg2l_gpio_irq_disable(struct irq_data *d) gpiochip_disable_irq(gc, hwirq); } -static void rzg2l_gpio_irq_enable(struct irq_data *d) +static void __rzg2l_gpio_irq_enable(struct irq_data *d, bool lock) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip); unsigned int hwirq = irqd_to_hwirq(d); gpiochip_enable_irq(gc, hwirq); + if (lock) + rzg2l_gpio_irq_endisable(pctrl, hwirq, true); + else + __rzg2l_gpio_irq_endisable(pctrl, hwirq, true); irq_chip_enable_parent(d); } -static int rzg2l_gpio_irq_set_type(struct irq_data *d, unsigned int type) -{ - return irq_chip_set_type_parent(d, type); -} - -static void rzg2l_gpio_irqc_eoi(struct irq_data *d) +static void rzg2l_gpio_irq_enable(struct irq_data *d) { - irq_chip_eoi_parent(d); + __rzg2l_gpio_irq_enable(d, true); } static void rzg2l_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p) @@ -2516,8 +2548,8 @@ static const struct irq_chip rzg2l_gpio_irqchip = { .irq_enable = rzg2l_gpio_irq_enable, .irq_mask = irq_chip_mask_parent, .irq_unmask = irq_chip_unmask_parent, - .irq_set_type = rzg2l_gpio_irq_set_type, - .irq_eoi = rzg2l_gpio_irqc_eoi, + .irq_set_type = irq_chip_set_type_parent, + .irq_eoi = irq_chip_eoi_parent, .irq_print_chip = rzg2l_gpio_irq_print_chip, .irq_set_affinity = irq_chip_set_affinity_parent, .irq_set_wake = rzg2l_gpio_irq_set_wake, @@ -2616,11 +2648,11 @@ static void rzg2l_gpio_irq_restore(struct rzg2l_pinctrl *pctrl) * This has to be atomically executed to protect against a concurrent * interrupt. */ - spin_lock_irqsave(&pctrl->lock, flags); - ret = rzg2l_gpio_irq_set_type(data, irqd_get_trigger_type(data)); + raw_spin_lock_irqsave(&pctrl->lock, flags); + ret = irq_chip_set_type_parent(data, irqd_get_trigger_type(data)); if (!ret && !irqd_irq_disabled(data)) - rzg2l_gpio_irq_enable(data); - spin_unlock_irqrestore(&pctrl->lock, flags); + __rzg2l_gpio_irq_enable(data, false); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); if (ret) dev_crit(pctrl->dev, "Failed to set IRQ type for virq=%u\n", virq); @@ -2950,7 +2982,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev) "failed to enable GPIO clk\n"); } - spin_lock_init(&pctrl->lock); + raw_spin_lock_init(&pctrl->lock); spin_lock_init(&pctrl->bitmap_lock); mutex_init(&pctrl->mutex); atomic_set(&pctrl->wakeup_path, 0); @@ -2993,7 +3025,11 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen * Now cache the registers or set them in the order suggested by * HW manual (section "Operation for GPIO Function"). */ - RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + PMC(off), cache->pmc[port]); + if (suspend) + RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + PMC(off), cache->pmc[port]); + else + pctrl->data->pmc_writeb(pctrl, cache->pmc[port], PMC(off)); + if (has_iolh) { RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IOLH(off), cache->iolh[0][port]); @@ -3093,7 +3129,7 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) u32 nports = pctrl->data->n_port_pins / RZG2L_PINS_PER_PORT; unsigned long flags; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); pctrl->data->pwpr_pfc_lock_unlock(pctrl, false); /* Restore port registers. */ @@ -3113,11 +3149,18 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) pm = readw(pctrl->base + PM(off)); for_each_set_bit(pin, &pinmap, max_pin) { struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache; + u32 pfc_val, pfc_mask; /* Nothing to do if PFC was not configured before. */ if (!(cache->pmc[port] & BIT(pin))) continue; + pfc_val = readl(pctrl->base + PFC(off)); + pfc_mask = PFC_MASK << (pin * 4); + /* Nothing to do if reset value of the pin is same as cached value */ + if ((cache->pfc[port] & pfc_mask) == (pfc_val & pfc_mask)) + continue; + /* Set pin to 'Non-use (Hi-Z input protection)' */ pm &= ~(PM_MASK << (pin * 2)); writew(pm, pctrl->base + PM(off)); @@ -3127,8 +3170,8 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) writeb(pmc, pctrl->base + PMC(off)); /* Select Pin function mode. */ - pfc &= ~(PFC_MASK << (pin * 4)); - pfc |= (cache->pfc[port] & (PFC_MASK << (pin * 4))); + pfc &= ~pfc_mask; + pfc |= (cache->pfc[port] & pfc_mask); writel(pfc, pctrl->base + PFC(off)); /* Switch to Peripheral pin function. */ @@ -3138,7 +3181,7 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) } pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_pinctrl_suspend_noirq(struct device *dev) @@ -3176,7 +3219,6 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) const struct rzg2l_register_offsets *regs = &hwcfg->regs; struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache; unsigned long flags; - u8 pwpr; int ret; if (!atomic_read(&pctrl->wakeup_path)) { @@ -3186,16 +3228,11 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) } writeb(cache->qspi, pctrl->base + QSPI); - if (pctrl->data->hwcfg->oen_pwpr_lock) { - spin_lock_irqsave(&pctrl->lock, flags); - pwpr = readb(pctrl->base + regs->pwpr); - writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); - } - writeb(cache->oen, pctrl->base + pctrl->data->hwcfg->regs.oen); - if (pctrl->data->hwcfg->oen_pwpr_lock) { - writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); - spin_unlock_irqrestore(&pctrl->lock, flags); - } + + raw_spin_lock_irqsave(&pctrl->lock, flags); + rzg2l_oen_write_with_pwpr(pctrl, cache->oen); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + for (u8 i = 0; i < 2; i++) { if (regs->sd_ch) writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i)); diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c index 3872638f5ebb..4826ff91cd90 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c +++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c @@ -144,7 +144,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl, /* Switch to Peripheral pin function with PMC register */ reg16 = rzt2h_pinctrl_readb(pctrl, port, PMC(port)); rzt2h_pinctrl_writeb(pctrl, port, reg16 | BIT(pin), PMC(port)); -}; +} static int rzt2h_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, @@ -182,7 +182,7 @@ static int rzt2h_pinctrl_set_mux(struct pinctrl_dev *pctldev, } return 0; -}; +} static int rzt2h_map_add_config(struct pinctrl_map *map, const char *group_or_pin, diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c index dce68f93d2d5..495e7f5d4128 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c +++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c @@ -155,7 +155,7 @@ static void rzv2m_pinctrl_set_pfc_mode(struct rzv2m_pinctrl *pctrl, /* Unmask input/output */ rzv2m_writel_we(pctrl->base + EN_MSK(port), pin, 0); rzv2m_writel_we(pctrl->base + DI_MSK(port), pin, 0); -}; +} static int rzv2m_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, @@ -186,7 +186,7 @@ static int rzv2m_pinctrl_set_mux(struct pinctrl_dev *pctldev, } return 0; -}; +} static int rzv2m_map_add_config(struct pinctrl_map *map, const char *group_or_pin, @@ -551,7 +551,7 @@ static int rzv2m_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, *config = pinconf_to_config_packed(param, arg); return 0; -}; +} static int rzv2m_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, unsigned int _pin, @@ -689,7 +689,7 @@ static int rzv2m_pinctrl_pinconf_group_set(struct pinctrl_dev *pctldev, } return 0; -}; +} static int rzv2m_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, unsigned int group, @@ -716,7 +716,7 @@ static int rzv2m_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, } return 0; -}; +} static const struct pinctrl_ops rzv2m_pinctrl_pctlops = { .get_groups_count = pinctrl_generic_get_group_count, diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c index 323487dfa8c2..627dca504d7a 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -1485,6 +1485,163 @@ const struct samsung_pinctrl_of_match_data exynosautov920_of_data __initconst = .num_ctrl = ARRAY_SIZE(exynosautov920_pin_ctrl), }; +/* pin banks of exynos8890 pin-controller 0 (ALIVE) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks0[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS7870_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), + EXYNOS7870_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04), + EXYNOS7870_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08), + EXYNOS7870_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c), +}; + +/* pin banks of exynos8890 pin-controller 1 (AUD) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks1[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(7, 0x000, "gph0", 0x00), +}; + +/* pin banks of exynos8890 pin-controller 2 (CCORE) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks2[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(2, 0x000, "etc0", 0x00), +}; + +/* pin banks of exynos8890 pin-controller 3 (ESE) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks3[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(5, 0x000, "gpf3", 0x00), +}; + +/* pin banks of exynos8890 pin-controller 4 (FP) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks4[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpf2", 0x00), +}; + +/* pin banks of exynos8890 pin-controller 5 (FSYS0) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks5[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpi1", 0x00), + EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpi2", 0x04), +}; + +/* pin banks of exynos8890 pin-controller 6 (FSYS1) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks6[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(7, 0x000, "gpj0", 0x00), +}; + +/* pin banks of exynos8890 pin-controller 7 (NFC) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks7[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpf0", 0x00), +}; + +/* pin banks of exynos8890 pin-controller 8 (PERIC0) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks8[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(6, 0x000, "gpi0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpd0", 0x04), + EXYNOS8895_PIN_BANK_EINTG(6, 0x040, "gpd1", 0x08), + EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpd2", 0x0c), + EXYNOS8895_PIN_BANK_EINTG(4, 0x080, "gpd3", 0x10), + EXYNOS8895_PIN_BANK_EINTG(2, 0x0A0, "gpb1", 0x14), + EXYNOS8895_PIN_BANK_EINTG(2, 0x0C0, "gpb2", 0x18), + EXYNOS8895_PIN_BANK_EINTG(3, 0x0E0, "gpb0", 0x1c), + EXYNOS8895_PIN_BANK_EINTG(5, 0x100, "gpc0", 0x20), + EXYNOS8895_PIN_BANK_EINTG(5, 0x120, "gpc1", 0x24), + EXYNOS8895_PIN_BANK_EINTG(6, 0x140, "gpc2", 0x28), + EXYNOS8895_PIN_BANK_EINTG(8, 0x160, "gpc3", 0x2c), + EXYNOS8895_PIN_BANK_EINTG(4, 0x180, "gpk0", 0x30), + EXYNOS8895_PIN_BANK_EINTG(7, 0x1A0, "etc1", 0x34), +}; + +/* pin banks of exynos8890 pin-controller 9 (PERIC1) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks9[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpe5", 0x04), + EXYNOS8895_PIN_BANK_EINTG(8, 0x040, "gpe6", 0x08), + EXYNOS8895_PIN_BANK_EINTG(8, 0x060, "gpj1", 0x0c), + EXYNOS8895_PIN_BANK_EINTG(2, 0x080, "gpj2", 0x10), + EXYNOS8895_PIN_BANK_EINTG(8, 0x0A0, "gpe2", 0x14), + EXYNOS8895_PIN_BANK_EINTG(8, 0x0C0, "gpe3", 0x18), + EXYNOS8895_PIN_BANK_EINTG(8, 0x0E0, "gpe4", 0x1c), + EXYNOS8895_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20), + EXYNOS8895_PIN_BANK_EINTG(4, 0x120, "gpe7", 0x24), + EXYNOS8895_PIN_BANK_EINTG(3, 0x140, "gpg0", 0x28), +}; + +/* pin banks of exynos8890 pin-controller 10 (TOUCH) */ +static const struct samsung_pin_bank_data exynos8890_pin_banks10[] __initconst = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpf1", 0x00), +}; + +static const struct samsung_pin_ctrl exynos8890_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 Alive data */ + .pin_banks = exynos8890_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks0), + .eint_wkup_init = exynos_eint_wkup_init, + }, { + /* pin-controller instance 1 AUD data */ + .pin_banks = exynos8890_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks1), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 2 CCORE data */ + .pin_banks = exynos8890_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 3 ESE data */ + .pin_banks = exynos8890_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 4 FP data */ + .pin_banks = exynos8890_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 5 FSYS0 data */ + .pin_banks = exynos8890_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 6 FSYS1 data */ + .pin_banks = exynos8890_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 7 NFC data */ + .pin_banks = exynos8890_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 8 PERIC0 data */ + .pin_banks = exynos8890_pin_banks8, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks8), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 9 PERIC1 data */ + .pin_banks = exynos8890_pin_banks9, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks9), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 10 TOUCH data */ + .pin_banks = exynos8890_pin_banks10, + .nr_banks = ARRAY_SIZE(exynos8890_pin_banks10), + .eint_gpio_init = exynos_eint_gpio_init, + }, +}; + +const struct samsung_pinctrl_of_match_data exynos8890_of_data __initconst = { + .ctrl = exynos8890_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos8890_pin_ctrl), +}; + /* pin banks of exynos8895 pin-controller 0 (ALIVE) */ static const struct samsung_pin_bank_data exynos8895_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa0", 0x00), @@ -1866,3 +2023,52 @@ const struct samsung_pinctrl_of_match_data artpec8_of_data __initconst = { .ctrl = artpec8_pin_ctrl, .num_ctrl = ARRAY_SIZE(artpec8_pin_ctrl), }; + +/* pin banks of artpec9 pin-controller (FSYS0) */ +static const struct samsung_pin_bank_data artpec9_pin_banks0[] __initconst = { + ARTPEC_PIN_BANK_EINTG(8, 0x000, "gpf0", 0x00), + ARTPEC_PIN_BANK_EINTG(8, 0x020, "gpf1", 0x04), + ARTPEC_PIN_BANK_EINTG(8, 0x040, "gpe0", 0x08), + ARTPEC_PIN_BANK_EINTG(8, 0x060, "gpe1", 0x0c), + ARTPEC_PIN_BANK_EINTG(8, 0x080, "gpe2", 0x10), + ARTPEC_PIN_BANK_EINTG(8, 0x0a0, "gpe3", 0x14), + ARTPEC_PIN_BANK_EINTG(2, 0x0c0, "gpe4", 0x18), + ARTPEC_PIN_BANK_EINTG(8, 0x0e0, "gps0", 0x1c), + ARTPEC_PIN_BANK_EINTG(8, 0x100, "gps1", 0x20), + ARTPEC_PIN_BANK_EINTG(5, 0x120, "gpi0", 0x24), +}; + +/* pin banks of artpec9 pin-controller (FSYS1) */ +static const struct samsung_pin_bank_data artpec9_pin_banks1[] __initconst = { + ARTPEC_PIN_BANK_EINTG(2, 0x000, "gpu0", 0x00), +}; + +/* pin banks of artpec9 pin-controller (PERIC) */ +static const struct samsung_pin_bank_data artpec9_pin_banks2[] __initconst = { + ARTPEC_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), + ARTPEC_PIN_BANK_EINTG(8, 0x020, "gpa1", 0x04), +}; + +static const struct samsung_pin_ctrl artpec9_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 FSYS0 data */ + .pin_banks = artpec9_pin_banks0, + .nr_banks = ARRAY_SIZE(artpec9_pin_banks0), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 1 FSYS1 data */ + .pin_banks = artpec9_pin_banks1, + .nr_banks = ARRAY_SIZE(artpec9_pin_banks1), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 2 PERIC data */ + .pin_banks = artpec9_pin_banks2, + .nr_banks = ARRAY_SIZE(artpec9_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + }, +}; + +const struct samsung_pinctrl_of_match_data artpec9_of_data __initconst = { + .ctrl = artpec9_pin_ctrl, + .num_ctrl = ARRAY_SIZE(artpec9_pin_ctrl), +}; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index c099195fc464..e374effba25a 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1484,6 +1484,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { #ifdef CONFIG_PINCTRL_EXYNOS_ARM64 { .compatible = "axis,artpec8-pinctrl", .data = &artpec8_of_data }, + { .compatible = "axis,artpec9-pinctrl", + .data = &artpec9_of_data }, { .compatible = "google,gs101-pinctrl", .data = &gs101_of_data }, { .compatible = "samsung,exynos2200-pinctrl", @@ -1498,6 +1500,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = &exynos7885_of_data }, { .compatible = "samsung,exynos850-pinctrl", .data = &exynos850_of_data }, + { .compatible = "samsung,exynos8890-pinctrl", + .data = &exynos8890_of_data }, { .compatible = "samsung,exynos8895-pinctrl", .data = &exynos8895_of_data }, { .compatible = "samsung,exynos9810-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 3e8ef91d94a3..0f7b2ea98158 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -382,6 +382,7 @@ struct samsung_pmx_func { /* list of all exported SoC specific data */ extern const struct samsung_pinctrl_of_match_data artpec8_of_data; +extern const struct samsung_pinctrl_of_match_data artpec9_of_data; extern const struct samsung_pinctrl_of_match_data exynos2200_of_data; extern const struct samsung_pinctrl_of_match_data exynos3250_of_data; extern const struct samsung_pinctrl_of_match_data exynos4210_of_data; @@ -395,6 +396,7 @@ extern const struct samsung_pinctrl_of_match_data exynos7_of_data; extern const struct samsung_pinctrl_of_match_data exynos7870_of_data; extern const struct samsung_pinctrl_of_match_data exynos7885_of_data; extern const struct samsung_pinctrl_of_match_data exynos850_of_data; +extern const struct samsung_pinctrl_of_match_data exynos8890_of_data; extern const struct samsung_pinctrl_of_match_data exynos8895_of_data; extern const struct samsung_pinctrl_of_match_data exynos9810_of_data; extern const struct samsung_pinctrl_of_match_data exynos990_of_data; diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c index cf42e204cbf0..3433b3c91692 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c @@ -29,7 +29,6 @@ #include "pinctrl-starfive-jh7110.h" #define JH7110_AON_NGPIO 4 -#define JH7110_AON_GC_BASE 64 #define JH7110_AON_REGS_NUM 37 @@ -138,7 +137,6 @@ static const struct jh7110_pinctrl_soc_info jh7110_aon_pinctrl_info = { .pins = jh7110_aon_pins, .npins = ARRAY_SIZE(jh7110_aon_pins), .ngpios = JH7110_AON_NGPIO, - .gc_base = JH7110_AON_GC_BASE, .dout_reg_base = JH7110_AON_DOUT, .dout_mask = GENMASK(3, 0), .doen_reg_base = JH7110_AON_DOEN, diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c index 03c2ad808d61..9b67063a0b0b 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c @@ -29,7 +29,6 @@ #include "pinctrl-starfive-jh7110.h" #define JH7110_SYS_NGPIO 64 -#define JH7110_SYS_GC_BASE 0 #define JH7110_SYS_REGS_NUM 174 @@ -410,7 +409,6 @@ static const struct jh7110_pinctrl_soc_info jh7110_sys_pinctrl_info = { .pins = jh7110_sys_pins, .npins = ARRAY_SIZE(jh7110_sys_pins), .ngpios = JH7110_SYS_NGPIO, - .gc_base = JH7110_SYS_GC_BASE, .dout_reg_base = JH7110_SYS_DOUT, .dout_mask = GENMASK(6, 0), .doen_reg_base = JH7110_SYS_DOEN, diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c index 05e3af75b09f..eb5cf8c067d1 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c @@ -938,7 +938,7 @@ int jh7110_pinctrl_probe(struct platform_device *pdev) sfp->gc.set = jh7110_gpio_set; sfp->gc.set_config = jh7110_gpio_set_config; sfp->gc.add_pin_ranges = jh7110_gpio_add_pin_ranges; - sfp->gc.base = info->gc_base; + sfp->gc.base = -1; sfp->gc.ngpio = info->ngpios; jh7110_irq_chip.name = sfp->gc.label; diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h index a33d0d4e1382..2da2d6858008 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h @@ -38,7 +38,6 @@ struct jh7110_pinctrl_soc_info { const struct pinctrl_pin_desc *pins; unsigned int npins; unsigned int ngpios; - unsigned int gc_base; /* gpio dout/doen/din/gpioinput register */ unsigned int dout_reg_base; diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 3ebb468de830..6a99708a5a23 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -51,20 +51,22 @@ #define STM32_GPIO_AFRL 0x20 #define STM32_GPIO_AFRH 0x24 #define STM32_GPIO_SECCFGR 0x30 +#define STM32_GPIO_DELAYRL 0x40 +#define STM32_GPIO_ADVCFGRL 0x48 #define STM32_GPIO_CIDCFGR(x) (0x50 + (0x8 * (x))) #define STM32_GPIO_SEMCR(x) (0x54 + (0x8 * (x))) -/* custom bitfield to backup pin status */ -#define STM32_GPIO_BKP_MODE_SHIFT 0 -#define STM32_GPIO_BKP_MODE_MASK GENMASK(1, 0) -#define STM32_GPIO_BKP_ALT_SHIFT 2 -#define STM32_GPIO_BKP_ALT_MASK GENMASK(5, 2) -#define STM32_GPIO_BKP_SPEED_SHIFT 6 -#define STM32_GPIO_BKP_SPEED_MASK GENMASK(7, 6) -#define STM32_GPIO_BKP_PUPD_SHIFT 8 -#define STM32_GPIO_BKP_PUPD_MASK GENMASK(9, 8) -#define STM32_GPIO_BKP_TYPE 10 -#define STM32_GPIO_BKP_VAL 11 +/* Unitary delay for STM32_GPIO_DELAYRL */ +#define STM32_GPIO_DELAYRL_PS 250 + +#define STM32_GPIO_ADVCFGR_DLYPATH_MASK BIT(0) +#define STM32_GPIO_ADVCFGR_DE_MASK BIT(1) +#define STM32_GPIO_ADVCFGR_INVCLK_MASK BIT(2) +#define STM32_GPIO_ADVCFGR_RET_MASK BIT(3) +#define STM32_GPIO_ADVCFGR_IO_SYNC_MASK \ + (STM32_GPIO_ADVCFGR_DE_MASK \ + | STM32_GPIO_ADVCFGR_INVCLK_MASK \ + | STM32_GPIO_ADVCFGR_RET_MASK) #define STM32_GPIO_CIDCFGR_CFEN BIT(0) #define STM32_GPIO_CIDCFGR_SEMEN BIT(1) @@ -79,6 +81,9 @@ #define SYSCFG_IRQMUX_MASK GENMASK(3, 0) +/* Vendor specific pin configuration */ +#define STM32_GPIO_PIN_CONFIG_IO_SYNC (PIN_CONFIG_END + 1) + #define gpio_range_to_bank(chip) \ container_of(chip, struct stm32_gpio_bank, range) @@ -94,12 +99,49 @@ static const char * const stm32_gpio_functions[] = { "reserved", }; +static const char * const stm32_gpio_io_sync[] = { + "pass-through", + "clock inverted", + "data on rising edge", + "data on falling edge", + "data on both edges", +}; + +static u8 io_sync_2_advcfgr[] = { + /* data or clock GPIO pass-through */ + [0] = 0, + /* clock GPIO inverted */ + [1] = STM32_GPIO_ADVCFGR_INVCLK_MASK, + /* data GPIO re-sampled on clock rising edge */ + [2] = STM32_GPIO_ADVCFGR_RET_MASK, + /* data GPIO re-sampled on clock falling edge */ + [3] = STM32_GPIO_ADVCFGR_RET_MASK | STM32_GPIO_ADVCFGR_INVCLK_MASK, + /* data GPIO re-sampled on both clock edges */ + [4] = STM32_GPIO_ADVCFGR_RET_MASK | STM32_GPIO_ADVCFGR_DE_MASK, +}; + +static const struct pinconf_generic_params stm32_gpio_bindings[] = { + {"st,io-sync", STM32_GPIO_PIN_CONFIG_IO_SYNC, 0, + stm32_gpio_io_sync, ARRAY_SIZE(stm32_gpio_io_sync)}, +}; + struct stm32_pinctrl_group { const char *name; unsigned long config; unsigned pin; }; +struct stm32_pin_backup { + unsigned int alt:4; + unsigned int mode:2; + unsigned int bias:2; + unsigned int speed:2; + unsigned int drive:1; + unsigned int value:1; + unsigned int advcfg:4; + unsigned int skew_delay:4; +}; + struct stm32_gpio_bank { void __iomem *base; struct reset_control *rstc; @@ -110,9 +152,10 @@ struct stm32_gpio_bank { struct irq_domain *domain; u32 bank_nr; u32 bank_ioport_nr; - u32 pin_backup[STM32_GPIO_PINS_PER_BANK]; + struct stm32_pin_backup pin_backup[STM32_GPIO_PINS_PER_BANK]; u8 irq_type[STM32_GPIO_PINS_PER_BANK]; bool secure_control; + bool io_sync_control; bool rif_control; }; @@ -176,38 +219,47 @@ static inline u32 stm32_gpio_get_alt(u32 function) static void stm32_gpio_backup_value(struct stm32_gpio_bank *bank, u32 offset, u32 value) { - bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_VAL); - bank->pin_backup[offset] |= value << STM32_GPIO_BKP_VAL; + bank->pin_backup[offset].value = value; } static void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, u32 offset, u32 mode, u32 alt) { - bank->pin_backup[offset] &= ~(STM32_GPIO_BKP_MODE_MASK | - STM32_GPIO_BKP_ALT_MASK); - bank->pin_backup[offset] |= mode << STM32_GPIO_BKP_MODE_SHIFT; - bank->pin_backup[offset] |= alt << STM32_GPIO_BKP_ALT_SHIFT; + bank->pin_backup[offset].mode = mode; + bank->pin_backup[offset].alt = alt; } static void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, u32 offset, u32 drive) { - bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_TYPE); - bank->pin_backup[offset] |= drive << STM32_GPIO_BKP_TYPE; + bank->pin_backup[offset].drive = drive; } static void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, u32 offset, u32 speed) { - bank->pin_backup[offset] &= ~STM32_GPIO_BKP_SPEED_MASK; - bank->pin_backup[offset] |= speed << STM32_GPIO_BKP_SPEED_SHIFT; + bank->pin_backup[offset].speed = speed; } static void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, u32 offset, u32 bias) { - bank->pin_backup[offset] &= ~STM32_GPIO_BKP_PUPD_MASK; - bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT; + bank->pin_backup[offset].bias = bias; +} + +static void stm32_gpio_backup_advcfg(struct stm32_gpio_bank *bank, u32 offset, u32 mask, u32 value) +{ + u32 val; + + val = bank->pin_backup[offset].advcfg; + val &= ~mask; + val |= value & mask; + bank->pin_backup[offset].advcfg = val; +} + +static void stm32_gpio_backup_skew_delay(struct stm32_gpio_bank *bank, u32 offset, u32 delay) +{ + bank->pin_backup[offset].skew_delay = delay; } /* RIF functions */ @@ -287,7 +339,7 @@ static void stm32_gpio_rif_release_semaphore(struct stm32_gpio_bank *bank, unsig /* GPIO functions */ static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank, - unsigned offset, int value) + unsigned int offset, u32 value) { stm32_gpio_backup_value(bank, offset, value); @@ -310,11 +362,9 @@ static int stm32_gpio_request(struct gpio_chip *chip, unsigned offset) return -EINVAL; } - if (bank->rif_control) { - if (!stm32_gpio_rif_acquire_semaphore(bank, offset)) { - dev_err(pctl->dev, "pin %d not available.\n", pin); - return -EINVAL; - } + if (bank->rif_control && !stm32_gpio_rif_acquire_semaphore(bank, offset)) { + dev_err(pctl->dev, "pin %d not available.\n", offset); + return -EACCES; } return pinctrl_gpio_request(chip, offset); @@ -929,9 +979,6 @@ static void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, u32 val; int alt_shift = (pin % 8) * 4; int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4; - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); val = readl_relaxed(bank->base + alt_offset); val &= GENMASK(alt_shift + 3, alt_shift); @@ -940,8 +987,6 @@ static void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, val = readl_relaxed(bank->base + STM32_GPIO_MODER); val &= GENMASK(pin * 2 + 1, pin * 2); *mode = val >> (pin * 2); - - spin_unlock_irqrestore(&bank->lock, flags); } static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, @@ -993,7 +1038,9 @@ static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, static int stm32_pmx_request(struct pinctrl_dev *pctldev, unsigned int gpio) { struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + unsigned int offset = stm32_gpio_pin(gpio); struct pinctrl_gpio_range *range; + struct stm32_gpio_bank *bank; range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, gpio); if (!range) { @@ -1001,11 +1048,20 @@ static int stm32_pmx_request(struct pinctrl_dev *pctldev, unsigned int gpio) return -EINVAL; } - if (!gpiochip_line_is_valid(range->gc, stm32_gpio_pin(gpio))) { + if (!gpiochip_line_is_valid(range->gc, offset)) { dev_warn(pctl->dev, "Can't access gpio %d\n", gpio); return -EACCES; } + bank = gpiochip_get_data(range->gc); + if (!bank) + return -ENODEV; + + if (bank->rif_control && !stm32_gpio_rif_acquire_semaphore(bank, offset)) { + dev_err(pctl->dev, "pin %d not available.\n", offset); + return -EACCES; + } + return 0; } @@ -1059,16 +1115,11 @@ unlock: static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, unsigned int offset) { - unsigned long flags; u32 val; - spin_lock_irqsave(&bank->lock, flags); - val = readl_relaxed(bank->base + STM32_GPIO_TYPER); val &= BIT(offset); - spin_unlock_irqrestore(&bank->lock, flags); - return (val >> offset); } @@ -1110,16 +1161,11 @@ unlock: static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, unsigned int offset) { - unsigned long flags; u32 val; - spin_lock_irqsave(&bank->lock, flags); - val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR); val &= GENMASK(offset * 2 + 1, offset * 2); - spin_unlock_irqrestore(&bank->lock, flags); - return (val >> (offset * 2)); } @@ -1161,27 +1207,168 @@ unlock: static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank, unsigned int offset) { - unsigned long flags; u32 val; - spin_lock_irqsave(&bank->lock, flags); - val = readl_relaxed(bank->base + STM32_GPIO_PUPDR); val &= GENMASK(offset * 2 + 1, offset * 2); + return (val >> (offset * 2)); +} + +static void +stm32_pconf_set_advcfgr_nolock(struct stm32_gpio_bank *bank, int offset, u32 mask, u32 value) +{ + int advcfgr_offset = STM32_GPIO_ADVCFGRL + (offset / 8) * 4; + int advcfgr_shift = (offset % 8) * 4; + u32 val; + + val = readl_relaxed(bank->base + advcfgr_offset); + val &= ~(mask << advcfgr_shift); + val |= (value & mask) << advcfgr_shift; + writel_relaxed(val, bank->base + advcfgr_offset); + + stm32_gpio_backup_advcfg(bank, offset, mask, value); +} + +static int stm32_pconf_set_advcfgr(struct stm32_gpio_bank *bank, int offset, u32 mask, u32 value) +{ + struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); + unsigned long flags; + int err = 0; + + if (!bank->io_sync_control) + return -ENOTSUPP; + + spin_lock_irqsave(&bank->lock, flags); + + if (pctl->hwlock) { + err = hwspin_lock_timeout_in_atomic(pctl->hwlock, HWSPNLCK_TIMEOUT); + if (err) { + dev_err(pctl->dev, "Can't get hwspinlock\n"); + goto unlock; + } + } + + stm32_pconf_set_advcfgr_nolock(bank, offset, mask, value); + + if (pctl->hwlock) + hwspin_unlock_in_atomic(pctl->hwlock); + +unlock: spin_unlock_irqrestore(&bank->lock, flags); - return (val >> (offset * 2)); + return err; } -static bool stm32_pconf_get(struct stm32_gpio_bank *bank, - unsigned int offset, bool dir) +static u32 stm32_pconf_get_advcfgr(struct stm32_gpio_bank *bank, int offset, u32 mask) +{ + int advcfgr_offset = STM32_GPIO_ADVCFGRL + (offset / 8) * 4; + int advcfgr_shift = (offset % 8) * 4; + u32 val; + + if (!bank->io_sync_control) + return 0; + + val = readl_relaxed(bank->base + advcfgr_offset); + val >>= advcfgr_shift; + + return val & mask; +} + +static int stm32_pconf_set_io_sync(struct stm32_gpio_bank *bank, int offset, u32 io_sync) +{ + if (io_sync >= ARRAY_SIZE(io_sync_2_advcfgr)) + return -EINVAL; + + return stm32_pconf_set_advcfgr(bank, offset, STM32_GPIO_ADVCFGR_IO_SYNC_MASK, + io_sync_2_advcfgr[io_sync]); +} + +static const char *stm32_pconf_get_io_sync_str(struct stm32_gpio_bank *bank, int offset) +{ + u32 io_sync = stm32_pconf_get_advcfgr(bank, offset, STM32_GPIO_ADVCFGR_IO_SYNC_MASK); + + if (io_sync & STM32_GPIO_ADVCFGR_RET_MASK) { + if (io_sync & STM32_GPIO_ADVCFGR_DE_MASK) + return "data GPIO re-sampled on both clock edges"; + + if (io_sync & STM32_GPIO_ADVCFGR_INVCLK_MASK) + return "data GPIO re-sampled on clock falling edge"; + + return "data GPIO re-sampled on clock rising edge"; + } + + if (io_sync & STM32_GPIO_ADVCFGR_INVCLK_MASK) + return "clock GPIO inverted"; + + return NULL; +} + +static int +stm32_pconf_set_skew_delay(struct stm32_gpio_bank *bank, int offset, u32 delay, bool is_dir_input) { + struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); + int delay_offset = STM32_GPIO_DELAYRL + (offset / 8) * 4; + int delay_shift = (offset % 8) * 4; unsigned long flags; + int err = 0; u32 val; + if (!bank->io_sync_control) + return -ENOTSUPP; + spin_lock_irqsave(&bank->lock, flags); + if (pctl->hwlock) { + err = hwspin_lock_timeout_in_atomic(pctl->hwlock, HWSPNLCK_TIMEOUT); + if (err) { + dev_err(pctl->dev, "Can't get hwspinlock\n"); + goto unlock; + } + } + + val = readl_relaxed(bank->base + delay_offset); + val &= ~GENMASK(delay_shift + 3, delay_shift); + val |= (delay << delay_shift); + writel_relaxed(val, bank->base + delay_offset); + + stm32_gpio_backup_skew_delay(bank, offset, delay); + + stm32_pconf_set_advcfgr_nolock(bank, offset, STM32_GPIO_ADVCFGR_DLYPATH_MASK, + is_dir_input ? STM32_GPIO_ADVCFGR_DLYPATH_MASK : 0); + + if (pctl->hwlock) + hwspin_unlock_in_atomic(pctl->hwlock); + +unlock: + spin_unlock_irqrestore(&bank->lock, flags); + + return err; +} + +static u32 stm32_pconf_get_skew_delay_val(struct stm32_gpio_bank *bank, int offset) +{ + int delay_offset = STM32_GPIO_DELAYRL + (offset / 8) * 4; + int delay_shift = (offset % 8) * 4; + u32 val; + + val = readl_relaxed(bank->base + delay_offset); + val &= GENMASK(delay_shift + 3, delay_shift); + + return val >> delay_shift; +} + +static const char *stm32_pconf_get_skew_dir_str(struct stm32_gpio_bank *bank, int offset) +{ + return stm32_pconf_get_advcfgr(bank, offset, STM32_GPIO_ADVCFGR_DLYPATH_MASK) ? + "input" : "output"; +} + +static bool stm32_pconf_get(struct stm32_gpio_bank *bank, + unsigned int offset, bool dir) +{ + bool val; + if (dir) val = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset)); @@ -1189,16 +1376,15 @@ static bool stm32_pconf_get(struct stm32_gpio_bank *bank, val = !!(readl_relaxed(bank->base + STM32_GPIO_ODR) & BIT(offset)); - spin_unlock_irqrestore(&bank->lock, flags); - return val; } static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, - unsigned int pin, enum pin_config_param param, - enum pin_config_param arg) + unsigned int pin, unsigned long config) { struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + unsigned int param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); struct pinctrl_gpio_range *range; struct stm32_gpio_bank *bank; int offset, ret = 0; @@ -1217,6 +1403,11 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, return -EACCES; } + if (bank->rif_control && !stm32_gpio_rif_acquire_semaphore(bank, offset)) { + dev_err(pctl->dev, "pin %d not available.\n", offset); + return -EACCES; + } + switch (param) { case PIN_CONFIG_DRIVE_PUSH_PULL: ret = stm32_pconf_set_driving(bank, offset, 0); @@ -1240,6 +1431,17 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, __stm32_gpio_set(bank, offset, arg); ret = stm32_pmx_gpio_set_direction(pctldev, range, pin, false); break; + case PIN_CONFIG_SKEW_DELAY_INPUT_PS: + arg /= STM32_GPIO_DELAYRL_PS; + ret = stm32_pconf_set_skew_delay(bank, offset, arg, true); + break; + case PIN_CONFIG_SKEW_DELAY_OUTPUT_PS: + arg /= STM32_GPIO_DELAYRL_PS; + ret = stm32_pconf_set_skew_delay(bank, offset, arg, false); + break; + case STM32_GPIO_PIN_CONFIG_IO_SYNC: + ret = stm32_pconf_set_io_sync(bank, offset, arg); + break; default: ret = -ENOTSUPP; } @@ -1267,9 +1469,7 @@ static int stm32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, for (i = 0; i < num_configs; i++) { mutex_lock(&pctldev->mutex); - ret = stm32_pconf_parse_conf(pctldev, g->pin, - pinconf_to_config_param(configs[i]), - pinconf_to_config_argument(configs[i])); + ret = stm32_pconf_parse_conf(pctldev, g->pin, configs[i]); mutex_unlock(&pctldev->mutex); if (ret < 0) return ret; @@ -1286,9 +1486,7 @@ static int stm32_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, int i, ret; for (i = 0; i < num_configs; i++) { - ret = stm32_pconf_parse_conf(pctldev, pin, - pinconf_to_config_param(configs[i]), - pinconf_to_config_argument(configs[i])); + ret = stm32_pconf_parse_conf(pctldev, pin, configs[i]); if (ret < 0) return ret; } @@ -1386,6 +1584,22 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, case 3: break; } + + if (bank->io_sync_control) { + const char *io_sync_str, *skew_dir_str; + u32 skew_delay; + + io_sync_str = stm32_pconf_get_io_sync_str(bank, offset); + skew_dir_str = stm32_pconf_get_skew_dir_str(bank, offset); + skew_delay = stm32_pconf_get_skew_delay_val(bank, offset); + + if (io_sync_str) + seq_printf(s, " - IO-sync: %s", io_sync_str); + + if (skew_delay) + seq_printf(s, " - Skew-delay: %u (%u ps) %s", skew_delay, + skew_delay * STM32_GPIO_DELAYRL_PS, skew_dir_str); + } } static const struct pinconf_ops stm32_pconf_ops = { @@ -1478,6 +1692,7 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct fwnode bank->bank_nr = bank_nr; bank->bank_ioport_nr = bank_ioport_nr; bank->secure_control = pctl->match_data->secure_control; + bank->io_sync_control = pctl->match_data->io_sync_control; bank->rif_control = pctl->match_data->rif_control; spin_lock_init(&bank->lock); @@ -1671,7 +1886,7 @@ int stm32_pctl_probe(struct platform_device *pdev) if (hwlock_id == -EPROBE_DEFER) return hwlock_id; } else { - pctl->hwlock = hwspin_lock_request_specific(hwlock_id); + pctl->hwlock = devm_hwspin_lock_request_specific(dev, hwlock_id); } spin_lock_init(&pctl->irqmux_lock); @@ -1720,6 +1935,8 @@ int stm32_pctl_probe(struct platform_device *pdev) pctl->pctl_desc.confops = &stm32_pconf_ops; pctl->pctl_desc.pctlops = &stm32_pctrl_ops; pctl->pctl_desc.pmxops = &stm32_pmx_ops; + pctl->pctl_desc.num_custom_params = ARRAY_SIZE(stm32_gpio_bindings); + pctl->pctl_desc.custom_params = stm32_gpio_bindings; pctl->dev = &pdev->dev; pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, @@ -1801,7 +2018,7 @@ static int __maybe_unused stm32_pinctrl_restore_gpio_regs( struct stm32_pinctrl *pctl, u32 pin) { const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin); - u32 val, alt, mode, offset = stm32_gpio_pin(pin); + u32 mode, offset = stm32_gpio_pin(pin); struct pinctrl_gpio_range *range; struct stm32_gpio_bank *bank; bool pin_is_irq; @@ -1811,49 +2028,56 @@ static int __maybe_unused stm32_pinctrl_restore_gpio_regs( if (!range) return 0; + bank = gpiochip_get_data(range->gc); + if (!gpiochip_line_is_valid(range->gc, offset)) return 0; + if (bank->rif_control && !stm32_gpio_rif_acquire_semaphore(bank, offset)) { + dev_err(pctl->dev, "pin %d not available.\n", offset); + return -EACCES; + } + pin_is_irq = gpiochip_line_is_irq(range->gc, offset); if (!desc || (!pin_is_irq && !desc->gpio_owner)) return 0; - bank = gpiochip_get_data(range->gc); - - alt = bank->pin_backup[offset] & STM32_GPIO_BKP_ALT_MASK; - alt >>= STM32_GPIO_BKP_ALT_SHIFT; - mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK; - mode >>= STM32_GPIO_BKP_MODE_SHIFT; - - ret = stm32_pmx_set_mode(bank, offset, mode, alt); + mode = bank->pin_backup[offset].mode; + ret = stm32_pmx_set_mode(bank, offset, mode, bank->pin_backup[offset].alt); if (ret) return ret; - if (mode == 1) { - val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL); - val = val >> STM32_GPIO_BKP_VAL; - __stm32_gpio_set(bank, offset, val); - } + if (mode == 1) + __stm32_gpio_set(bank, offset, bank->pin_backup[offset].value); - val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE); - val >>= STM32_GPIO_BKP_TYPE; - ret = stm32_pconf_set_driving(bank, offset, val); + ret = stm32_pconf_set_driving(bank, offset, bank->pin_backup[offset].drive); if (ret) return ret; - val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK; - val >>= STM32_GPIO_BKP_SPEED_SHIFT; - ret = stm32_pconf_set_speed(bank, offset, val); + ret = stm32_pconf_set_speed(bank, offset, bank->pin_backup[offset].speed); if (ret) return ret; - val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK; - val >>= STM32_GPIO_BKP_PUPD_SHIFT; - ret = stm32_pconf_set_bias(bank, offset, val); + ret = stm32_pconf_set_bias(bank, offset, bank->pin_backup[offset].bias); if (ret) return ret; + if (bank->io_sync_control) { + bool is_input = bank->pin_backup[offset].advcfg & STM32_GPIO_ADVCFGR_DLYPATH_MASK; + + ret = stm32_pconf_set_skew_delay(bank, offset, + bank->pin_backup[offset].skew_delay, + is_input); + if (ret) + return ret; + + ret = stm32_pconf_set_advcfgr(bank, offset, STM32_GPIO_ADVCFGR_IO_SYNC_MASK, + bank->pin_backup[offset].advcfg); + if (ret) + return ret; + } + if (pin_is_irq) regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h index b98a4141bf2c..d17cbdbba448 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.h +++ b/drivers/pinctrl/stm32/pinctrl-stm32.h @@ -64,6 +64,7 @@ struct stm32_pinctrl_match_data { const struct stm32_desc_pin *pins; const unsigned int npins; bool secure_control; + bool io_sync_control; bool rif_control; }; diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp257.c b/drivers/pinctrl/stm32/pinctrl-stm32mp257.c index d226de524bfc..6709bddd9718 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32mp257.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32mp257.c @@ -2543,6 +2543,7 @@ static const struct stm32_desc_pin stm32mp257_z_pins[] = { static struct stm32_pinctrl_match_data stm32mp257_match_data = { .pins = stm32mp257_pins, .npins = ARRAY_SIZE(stm32mp257_pins), + .io_sync_control = true, .secure_control = true, .rif_control = true, }; @@ -2550,6 +2551,7 @@ static struct stm32_pinctrl_match_data stm32mp257_match_data = { static struct stm32_pinctrl_match_data stm32mp257_z_match_data = { .pins = stm32mp257_z_pins, .npins = ARRAY_SIZE(stm32mp257_z_pins), + .io_sync_control = true, .secure_control = true, .rif_control = true, }; diff --git a/drivers/pinctrl/tegra/pinctrl-tegra20.c b/drivers/pinctrl/tegra/pinctrl-tegra20.c index 737fc2000f66..1a1758fd7def 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra20.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra20.c @@ -2222,14 +2222,18 @@ static const struct tegra_pinctrl_soc_data tegra20_pinctrl = { .drvtype_in_mux = false, }; -static const char *cdev1_parents[] = { +static const char * const cdev1_parents[] = { "dev1_osc_div", "pll_a_out0", "pll_m_out1", "audio", }; -static const char *cdev2_parents[] = { +static const char * const cdev2_parents[] = { "dev2_osc_div", "hclk", "pclk", "pll_p_out4", }; +static const char * const csus_parents[] = { + "pll_c_out1", "pll_p_out2", "pll_p_out3", "vi_sensor", +}; + static void tegra20_pinctrl_register_clock_muxes(struct platform_device *pdev) { struct tegra_pmx *pmx = platform_get_drvdata(pdev); @@ -2239,6 +2243,9 @@ static void tegra20_pinctrl_register_clock_muxes(struct platform_device *pdev) clk_register_mux(NULL, "cdev2_mux", cdev2_parents, 4, 0, pmx->regs[1] + 0x8, 4, 2, CLK_MUX_READ_ONLY, NULL); + + clk_register_mux(NULL, "csus_mux", csus_parents, 4, 0, + pmx->regs[1] + 0x8, 6, 2, CLK_MUX_READ_ONLY, NULL); } static int tegra20_pinctrl_probe(struct platform_device *pdev) diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 324c69c63f76..312788f249c9 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -20,3 +20,5 @@ source "drivers/platform/x86/Kconfig" source "drivers/platform/arm64/Kconfig" source "drivers/platform/raspberrypi/Kconfig" + +source "drivers/platform/wmi/Kconfig" diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index b0935c602ada..fa322e7f8716 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/ obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/ obj-$(CONFIG_BCM2835_VCHIQ) += raspberrypi/ +obj-$(CONFIG_ACPI_WMI) += wmi/ diff --git a/drivers/platform/arm64/lenovo-thinkpad-t14s.c b/drivers/platform/arm64/lenovo-thinkpad-t14s.c index cf6a1d3b2617..5590302a5694 100644 --- a/drivers/platform/arm64/lenovo-thinkpad-t14s.c +++ b/drivers/platform/arm64/lenovo-thinkpad-t14s.c @@ -20,19 +20,23 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/pm.h> #define T14S_EC_CMD_ECRD 0x02 #define T14S_EC_CMD_ECWR 0x03 #define T14S_EC_CMD_EVT 0xf0 -#define T14S_EC_REG_LED 0x0c -#define T14S_EC_REG_KBD_BL1 0x0d -#define T14S_EC_REG_KBD_BL2 0xe1 -#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6) -#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2) -#define T14S_EC_REG_AUD 0x30 -#define T14S_EC_MIC_MUTE_LED BIT(5) -#define T14S_EC_SPK_MUTE_LED BIT(6) +#define T14S_EC_REG_LED 0x0c +#define T14S_EC_REG_KBD_BL1 0x0d +#define T14S_EC_REG_MODERN_STANDBY 0xe0 +#define T14S_EC_MODERN_STANDBY_ENTRY BIT(1) +#define T14S_EC_MODERN_STANDBY_EXIT BIT(0) +#define T14S_EC_REG_KBD_BL2 0xe1 +#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6) +#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2) +#define T14S_EC_REG_AUD 0x30 +#define T14S_EC_MIC_MUTE_LED BIT(5) +#define T14S_EC_SPK_MUTE_LED BIT(6) #define T14S_EC_EVT_NONE 0x00 #define T14S_EC_EVT_KEY_FN_4 0x13 @@ -202,6 +206,14 @@ out: return ret; } +static void t14s_ec_write_sequence(struct t14s_ec *ec, u8 reg, u8 val, u8 cnt) +{ + int i; + + for (i = 0; i < cnt; i++) + regmap_write(ec->regmap, reg, val); +} + static int t14s_led_set_status(struct t14s_ec *ec, struct t14s_ec_led_classdev *led, const enum t14s_ec_led_status_t ledstatus) @@ -554,6 +566,7 @@ static int t14s_ec_probe(struct i2c_client *client) return -ENOMEM; ec->dev = dev; + i2c_set_clientdata(client, ec); ec->regmap = devm_regmap_init(dev, &t14s_ec_regmap_bus, ec, &t14s_ec_regmap_config); @@ -593,6 +606,30 @@ static int t14s_ec_probe(struct i2c_client *client) return 0; } +static int t14s_ec_suspend(struct device *dev) +{ + struct t14s_ec *ec = dev_get_drvdata(dev); + + led_classdev_suspend(&ec->kbd_backlight); + + t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY, + T14S_EC_MODERN_STANDBY_ENTRY, 3); + + return 0; +} + +static int t14s_ec_resume(struct device *dev) +{ + struct t14s_ec *ec = dev_get_drvdata(dev); + + t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY, + T14S_EC_MODERN_STANDBY_EXIT, 3); + + led_classdev_resume(&ec->kbd_backlight); + + return 0; +} + static const struct of_device_id t14s_ec_of_match[] = { { .compatible = "lenovo,thinkpad-t14s-ec" }, {} @@ -605,10 +642,15 @@ static const struct i2c_device_id t14s_ec_i2c_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, t14s_ec_i2c_id_table); +static const struct dev_pm_ops t14s_ec_pm_ops = { + SYSTEM_SLEEP_PM_OPS(t14s_ec_suspend, t14s_ec_resume) +}; + static struct i2c_driver t14s_ec_i2c_driver = { .driver = { .name = "thinkpad-t14s-ec", .of_match_table = t14s_ec_of_match, + .pm = &t14s_ec_pm_ops, }, .probe = t14s_ec_probe, .id_table = t14s_ec_i2c_id_table, diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index c58e1fdd1a5f..c7e05f7bc199 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -676,7 +676,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) status = ssam_serdev_setup(ssh, serdev); if (status) { - status = dev_err_probe(dev, status, "failed to setup serdev\n"); + dev_err_probe(dev, status, "failed to setup serdev\n"); goto err_devinit; } diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c index 6081b0146d5f..3dd22856570f 100644 --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c @@ -671,7 +671,7 @@ static void ssh_ptl_timeout_reaper_mod(struct ssh_ptl *ptl, ktime_t now, /* Re-adjust / schedule reaper only if it is above resolution delta. */ if (ktime_before(aexp, ptl->rtx_timeout.expires)) { ptl->rtx_timeout.expires = expires; - mod_delayed_work(system_wq, &ptl->rtx_timeout.reaper, delta); + mod_delayed_work(system_percpu_wq, &ptl->rtx_timeout.reaper, delta); } spin_unlock(&ptl->rtx_timeout.lock); diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c index 879ca9ee7ff6..a356e4956562 100644 --- a/drivers/platform/surface/aggregator/ssh_request_layer.c +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c @@ -434,7 +434,7 @@ static void ssh_rtl_timeout_reaper_mod(struct ssh_rtl *rtl, ktime_t now, /* Re-adjust / schedule reaper only if it is above resolution delta. */ if (ktime_before(aexp, rtl->rtx_timeout.expires)) { rtl->rtx_timeout.expires = expires; - mod_delayed_work(system_wq, &rtl->rtx_timeout.reaper, delta); + mod_delayed_work(system_percpu_wq, &rtl->rtx_timeout.reaper, delta); } spin_unlock(&rtl->rtx_timeout.lock); diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index 3b30cfe3466b..a9dcb0bbe90e 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -862,7 +862,7 @@ static int __init san_init(void) { int ret; - san_wq = alloc_workqueue("san_wq", 0, 0); + san_wq = alloc_workqueue("san_wq", WQ_PERCPU, 0); if (!san_wq) return -ENOMEM; ret = platform_driver_register(&surface_acpi_notify); diff --git a/drivers/platform/wmi/Kconfig b/drivers/platform/wmi/Kconfig new file mode 100644 index 000000000000..77fcbb18746b --- /dev/null +++ b/drivers/platform/wmi/Kconfig @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# ACPI WMI Core +# + +menuconfig ACPI_WMI + tristate "ACPI-WMI support" + depends on ACPI && X86 + help + This option enables support for the ACPI-WMI driver core. + + The ACPI-WMI interface is a proprietary extension of ACPI allowing + the platform firmware to expose WMI (Windows Management Instrumentation) + objects used for managing various aspects of the underlying system. + Mapping between ACPI control methods and WMI objects happens through + special mapper devices (PNP0C14) defined inside the ACPI tables. + + Enabling this option is necessary for building the vendor specific + ACPI-WMI client drivers for Acer, Dell an HP machines (among others). + + It is safe to enable this option even for machines that do not contain + any ACPI-WMI mapper devices at all. + +if ACPI_WMI + +config ACPI_WMI_LEGACY_DEVICE_NAMES + bool "Use legacy WMI device naming scheme" + help + Say Y here to force the WMI driver core to use the old WMI device naming + scheme when creating WMI devices. Doing so might be necessary for some + userspace applications but will cause the registration of WMI devices with + the same GUID to fail in some corner cases. + +endif # ACPI_WMI diff --git a/drivers/platform/wmi/Makefile b/drivers/platform/wmi/Makefile new file mode 100644 index 000000000000..98393d7391ec --- /dev/null +++ b/drivers/platform/wmi/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for linux/drivers/platform/wmi +# ACPI WMI core +# + +wmi-y := core.o +obj-$(CONFIG_ACPI_WMI) += wmi.o diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/wmi/core.c index 4e86a422f05f..6878c4fcb0b5 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/wmi/core.c @@ -142,14 +142,6 @@ static inline void get_acpi_method_name(const struct wmi_block *wblock, buffer[4] = '\0'; } -static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wblock) -{ - if (wblock->gblock.flags & ACPI_WMI_STRING) - return ACPI_TYPE_STRING; - else - return ACPI_TYPE_BUFFER; -} - static int wmidev_match_guid(struct device *dev, const void *data) { struct wmi_block *wblock = dev_to_wblock(dev); @@ -351,9 +343,16 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met params[0].integer.value = instance; params[1].type = ACPI_TYPE_INTEGER; params[1].integer.value = method_id; - params[2].type = get_param_acpi_type(wblock); - params[2].buffer.length = in->length; - params[2].buffer.pointer = in->pointer; + + if (wblock->gblock.flags & ACPI_WMI_STRING) { + params[2].type = ACPI_TYPE_STRING; + params[2].string.length = in->length; + params[2].string.pointer = in->pointer; + } else { + params[2].type = ACPI_TYPE_BUFFER; + params[2].buffer.length = in->length; + params[2].buffer.pointer = in->pointer; + } get_acpi_method_name(wblock, 'M', method); @@ -519,9 +518,16 @@ acpi_status wmidev_block_set(struct wmi_device *wdev, u8 instance, const struct input.pointer = params; params[0].type = ACPI_TYPE_INTEGER; params[0].integer.value = instance; - params[1].type = get_param_acpi_type(wblock); - params[1].buffer.length = in->length; - params[1].buffer.pointer = in->pointer; + + if (wblock->gblock.flags & ACPI_WMI_STRING) { + params[1].type = ACPI_TYPE_STRING; + params[1].string.length = in->length; + params[1].string.pointer = in->pointer; + } else { + params[1].type = ACPI_TYPE_BUFFER; + params[1].buffer.length = in->length; + params[1].buffer.pointer = in->pointer; + } get_acpi_method_name(wblock, 'S', method); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index c883a28e0916..4cb7d97a9fcc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -16,36 +16,6 @@ menuconfig X86_PLATFORM_DEVICES if X86_PLATFORM_DEVICES -config ACPI_WMI - tristate "WMI" - depends on ACPI - help - This driver adds support for the ACPI-WMI (Windows Management - Instrumentation) mapper device (PNP0C14) found on some systems. - - ACPI-WMI is a proprietary extension to ACPI to expose parts of the - ACPI firmware to userspace - this is done through various vendor - defined methods and data blocks in a PNP0C14 device, which are then - made available for userspace to call. - - The implementation of this in Linux currently only exposes this to - other kernel space drivers. - - This driver is a required dependency to build the firmware specific - drivers needed on many machines, including Acer and HP laptops. - - It is safe to enable this driver even if your DSDT doesn't define - any ACPI-WMI devices. - -config ACPI_WMI_LEGACY_DEVICE_NAMES - bool "Use legacy WMI device naming scheme" - depends on ACPI_WMI - help - Say Y here to force the WMI driver core to use the old WMI device naming - scheme when creating WMI devices. Doing so might be necessary for some - userspace applications but will cause the registration of WMI devices with - the same GUID to fail in some corner cases. - config WMI_BMOF tristate "WMI embedded Binary MOF driver" depends on ACPI_WMI @@ -74,6 +44,8 @@ config HUAWEI_WMI To compile this driver as a module, choose M here: the module will be called huawei-wmi. +source "drivers/platform/x86/uniwill/Kconfig" + config UV_SYSFS tristate "Sysfs structure for UV systems" depends on X86_UV @@ -262,6 +234,18 @@ config ASUS_WIRELESS If you choose to compile this driver as a module the module will be called asus-wireless. +config ASUS_ARMOURY + tristate "ASUS Armoury driver" + depends on ASUS_WMI + select FW_ATTR_CLASS + help + Say Y here if you have a WMI aware Asus machine and would like to use the + firmware_attributes API to control various settings typically exposed in + the ASUS Armoury Crate application available on Windows. + + To compile this driver as a module, choose M here: the module will + be called asus-armoury. + config ASUS_WMI tristate "ASUS WMI Driver" depends on ACPI_WMI @@ -284,6 +268,17 @@ config ASUS_WMI To compile this driver as a module, choose M here: the module will be called asus-wmi. +config ASUS_WMI_DEPRECATED_ATTRS + bool "BIOS option support in WMI platform (DEPRECATED)" + depends on ASUS_WMI + default y + help + Say Y to expose the configurable BIOS options through the asus-wmi + driver. + + This can be used with or without the asus-armoury driver which + has the same attributes, but more, and better features. + config ASUS_NB_WMI tristate "Asus Notebook WMI Driver" depends on ASUS_WMI @@ -316,6 +311,19 @@ config ASUS_TF103C_DOCK If you have an Asus TF103C tablet say Y or M here, for a generic x86 distro config say M here. +config AYANEO_EC + tristate "Ayaneo EC platform control" + depends on DMI + depends on ACPI_EC + depends on ACPI_BATTERY + depends on HWMON + help + Enables support for the platform EC of Ayaneo devices. This + includes fan control, fan speed, charge limit, magic + module detection, and controller power control. + + If you have an Ayaneo device, say Y or M here. + config MERAKI_MX100 tristate "Cisco Meraki MX100 Platform Driver" depends on GPIOLIB @@ -1031,9 +1039,7 @@ config OXP_EC help Enables support for the platform EC of OneXPlayer and AOKZOE handheld devices. This includes fan speed, fan controls, and - disabling the default TDP behavior of the device. Due to legacy - reasons, this driver also provides hwmon functionality to Ayaneo - devices and the OrangePi Neo. + disabling the default TDP behavior of the device. source "drivers/platform/x86/tuxedo/Kconfig" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index c7db2a88c11a..d25762f7114f 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -5,7 +5,6 @@ # # Windows Management Interface -obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o # WMI drivers @@ -33,12 +32,16 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o # ASUS obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o +obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o obj-$(CONFIG_ASUS_WMI) += asus-wmi.o obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o +# Ayaneo +obj-$(CONFIG_AYANEO_EC) += ayaneo-ec.o + # Cisco/Meraki obj-$(CONFIG_MERAKI_MX100) += meraki-mx100.o @@ -110,6 +113,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o # before toshiba_acpi initializes obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o +# Uniwill +obj-y += uniwill/ + # Inspur obj-$(CONFIG_INSPUR_PLATFORM_PROFILE) += inspur_platform_profile.o diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index d848afc91f87..bf97381faf58 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -12,10 +12,12 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> #include <linux/dmi.h> +#include <linux/fixp-arith.h> #include <linux/backlight.h> #include <linux/leds.h> #include <linux/platform_device.h> @@ -68,10 +70,27 @@ MODULE_LICENSE("GPL"); #define ACER_WMID_SET_GAMING_LED_METHODID 2 #define ACER_WMID_GET_GAMING_LED_METHODID 4 #define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5 -#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14 +#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14 +#define ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID 15 +#define ACER_WMID_SET_GAMING_FAN_SPEED_METHODID 16 +#define ACER_WMID_GET_GAMING_FAN_SPEED_METHODID 17 #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 #define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23 +#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0) +#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3) + +#define ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK GENMASK_ULL(7, 0) +#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0) +#define ACER_GAMING_FAN_BEHAVIOR_SET_CPU_MODE_MASK GENMASK(17, 16) +#define ACER_GAMING_FAN_BEHAVIOR_SET_GPU_MODE_MASK GENMASK(23, 22) +#define ACER_GAMING_FAN_BEHAVIOR_GET_CPU_MODE_MASK GENMASK(9, 8) +#define ACER_GAMING_FAN_BEHAVIOR_GET_GPU_MODE_MASK GENMASK(15, 14) + +#define ACER_GAMING_FAN_SPEED_STATUS_MASK GENMASK_ULL(7, 0) +#define ACER_GAMING_FAN_SPEED_ID_MASK GENMASK_ULL(7, 0) +#define ACER_GAMING_FAN_SPEED_VALUE_MASK GENMASK_ULL(15, 8) + #define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0) #define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0) #define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8) @@ -122,6 +141,17 @@ enum acer_wmi_predator_v4_sensor_id { ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A, }; +enum acer_wmi_gaming_fan_id { + ACER_WMID_CPU_FAN = 0x01, + ACER_WMID_GPU_FAN = 0x04, +}; + +enum acer_wmi_gaming_fan_mode { + ACER_WMID_FAN_MODE_AUTO = 0x01, + ACER_WMID_FAN_MODE_TURBO = 0x02, + ACER_WMID_FAN_MODE_CUSTOM = 0x03, +}; + enum acer_wmi_predator_v4_oc { ACER_WMID_OC_NORMAL = 0x0000, ACER_WMID_OC_TURBO = 0x0002, @@ -279,6 +309,7 @@ struct hotkey_function_type_aa { #define ACER_CAP_TURBO_FAN BIT(9) #define ACER_CAP_PLATFORM_PROFILE BIT(10) #define ACER_CAP_HWMON BIT(11) +#define ACER_CAP_PWM BIT(12) /* * Interface type flags @@ -373,6 +404,7 @@ struct quirk_entry { u8 cpu_fans; u8 gpu_fans; u8 predator_v4; + u8 pwm; }; static struct quirk_entry *quirks; @@ -392,6 +424,9 @@ static void __init set_quirks(void) if (quirks->predator_v4) interface->capability |= ACER_CAP_PLATFORM_PROFILE | ACER_CAP_HWMON; + + if (quirks->pwm) + interface->capability |= ACER_CAP_PWM; } static int __init dmi_matched(const struct dmi_system_id *dmi) @@ -431,6 +466,7 @@ static struct quirk_entry quirk_acer_predator_ph16_72 = { .cpu_fans = 1, .gpu_fans = 1, .predator_v4 = 1, + .pwm = 1, }; static struct quirk_entry quirk_acer_predator_pt14_51 = { @@ -438,6 +474,7 @@ static struct quirk_entry quirk_acer_predator_pt14_51 = { .cpu_fans = 1, .gpu_fans = 1, .predator_v4 = 1, + .pwm = 1, }; static struct quirk_entry quirk_acer_predator_v4 = { @@ -658,6 +695,15 @@ static const struct dmi_system_id acer_quirks[] __initconst = { }, { .callback = dmi_matched, + .ident = "Acer Predator Helios Neo 16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Predator PHN16-72"), + }, + .driver_data = &quirk_acer_predator_ph16_72, + }, + { + .callback = dmi_matched, .ident = "Acer Predator PH18-71", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -1564,9 +1610,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap) case ACER_CAP_TURBO_LED: method_id = ACER_WMID_SET_GAMING_LED_METHODID; break; - case ACER_CAP_TURBO_FAN: - method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR; - break; default: return AE_BAD_PARAMETER; } @@ -1617,25 +1660,125 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out) return 0; } -static void WMID_gaming_set_fan_mode(u8 fan_mode) +static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, enum acer_wmi_gaming_fan_mode mode) { - /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/ - u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0; - int i; + acpi_status status; + u64 input = 0; + u64 result; + + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); + + if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_CPU) + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_CPU_MODE_MASK, mode); + + if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_GPU) + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_GPU_MODE_MASK, mode); + + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input, + &result); + if (ACPI_FAILURE(status)) + return -EIO; + + /* The return status must be zero for the operation to have succeeded */ + if (FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK, result)) + return -EIO; + + return 0; +} + +static int WMID_gaming_get_fan_behavior(u16 fan_bitmap, enum acer_wmi_gaming_fan_mode *mode) +{ + acpi_status status; + u32 input = 0; + u64 result; + int value; + + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); + status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID, input, + &result); + if (ACPI_FAILURE(status)) + return -EIO; + + /* The return status must be zero for the operation to have succeeded */ + if (FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK, result)) + return -EIO; + + /* Theoretically multiple fans can be specified, but this is currently unused */ + if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_CPU) + value = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GET_CPU_MODE_MASK, result); + else if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_GPU) + value = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GET_GPU_MODE_MASK, result); + else + return -EINVAL; + + if (value < ACER_WMID_FAN_MODE_AUTO || value > ACER_WMID_FAN_MODE_CUSTOM) + return -ENXIO; + + *mode = value; + + return 0; +} + +static void WMID_gaming_set_fan_mode(enum acer_wmi_gaming_fan_mode mode) +{ + u16 fan_bitmap = 0; if (quirks->cpu_fans > 0) - gpu_fan_config2 |= 1; - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) - gpu_fan_config2 |= 1 << (i + 1); - for (i = 0; i < quirks->gpu_fans; ++i) - gpu_fan_config2 |= 1 << (i + 3); - if (quirks->cpu_fans > 0) - gpu_fan_config1 |= fan_mode; - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) - gpu_fan_config1 |= fan_mode << (2 * i + 2); - for (i = 0; i < quirks->gpu_fans; ++i) - gpu_fan_config1 |= fan_mode << (2 * i + 6); - WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN); + fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_CPU; + + if (quirks->gpu_fans > 0) + fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_GPU; + + WMID_gaming_set_fan_behavior(fan_bitmap, mode); +} + +static int WMID_gaming_set_gaming_fan_speed(u8 fan, u8 speed) +{ + acpi_status status; + u64 input = 0; + u64 result; + + if (speed > 100) + return -EINVAL; + + input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan); + input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_VALUE_MASK, speed); + + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_SPEED_METHODID, input, &result); + if (ACPI_FAILURE(status)) + return -EIO; + + switch (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result)) { + case 0x00: + return 0; + case 0x01: + return -ENODEV; + case 0x02: + return -EINVAL; + default: + return -ENXIO; + } +} + +static int WMID_gaming_get_gaming_fan_speed(u8 fan, u8 *speed) +{ + acpi_status status; + u32 input = 0; + u64 result; + + input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan); + + status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_SPEED_METHODID, input, + &result); + if (ACPI_FAILURE(status)) + return -EIO; + + if (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result)) + return -ENODEV; + + *speed = FIELD_GET(ACER_GAMING_FAN_SPEED_VALUE_MASK, result); + + return 0; } static int WMID_gaming_set_misc_setting(enum acer_wmi_gaming_misc_setting setting, u8 value) @@ -1922,7 +2065,7 @@ static int acer_toggle_turbo(void) WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED); /* Set FAN mode to auto */ - WMID_gaming_set_fan_mode(0x1); + WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_AUTO); /* Set OC to normal */ if (has_cap(ACER_CAP_TURBO_OC)) { @@ -1936,7 +2079,7 @@ static int acer_toggle_turbo(void) WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED); /* Set FAN mode to turbo */ - WMID_gaming_set_fan_mode(0x2); + WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_TURBO); /* Set OC to turbo mode */ if (has_cap(ACER_CAP_TURBO_OC)) { @@ -2767,6 +2910,16 @@ static const enum acer_wmi_predator_v4_sensor_id acer_wmi_fan_channel_to_sensor_ [1] = ACER_WMID_SENSOR_GPU_FAN_SPEED, }; +static const enum acer_wmi_gaming_fan_id acer_wmi_fan_channel_to_fan_id[] = { + [0] = ACER_WMID_CPU_FAN, + [1] = ACER_WMID_GPU_FAN, +}; + +static const u16 acer_wmi_fan_channel_to_fan_bitmap[] = { + [0] = ACER_GAMING_FAN_BEHAVIOR_CPU, + [1] = ACER_GAMING_FAN_BEHAVIOR_GPU, +}; + static umode_t acer_wmi_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -2778,6 +2931,11 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data, case hwmon_temp: sensor_id = acer_wmi_temp_channel_to_sensor_id[channel]; break; + case hwmon_pwm: + if (!has_cap(ACER_CAP_PWM)) + return 0; + + fallthrough; case hwmon_fan: sensor_id = acer_wmi_fan_channel_to_sensor_id[channel]; break; @@ -2785,8 +2943,12 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data, return 0; } - if (*supported_sensors & BIT(sensor_id - 1)) + if (*supported_sensors & BIT(sensor_id - 1)) { + if (type == hwmon_pwm) + return 0644; + return 0444; + } return 0; } @@ -2795,6 +2957,9 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { u64 command = ACER_WMID_CMD_GET_PREDATOR_V4_SENSOR_READING; + enum acer_wmi_gaming_fan_mode mode; + u16 fan_bitmap; + u8 fan, speed; u64 result; int ret; @@ -2820,6 +2985,80 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, *val = FIELD_GET(ACER_PREDATOR_V4_SENSOR_READING_BIT_MASK, result); return 0; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + fan = acer_wmi_fan_channel_to_fan_id[channel]; + ret = WMID_gaming_get_gaming_fan_speed(fan, &speed); + if (ret < 0) + return ret; + + *val = fixp_linear_interpolate(0, 0, 100, U8_MAX, speed); + return 0; + case hwmon_pwm_enable: + fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel]; + ret = WMID_gaming_get_fan_behavior(fan_bitmap, &mode); + if (ret < 0) + return ret; + + switch (mode) { + case ACER_WMID_FAN_MODE_AUTO: + *val = 2; + return 0; + case ACER_WMID_FAN_MODE_TURBO: + *val = 0; + return 0; + case ACER_WMID_FAN_MODE_CUSTOM: + *val = 1; + return 0; + default: + return -ENXIO; + } + default: + return -EOPNOTSUPP; + } + default: + return -EOPNOTSUPP; + } +} + +static int acer_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + enum acer_wmi_gaming_fan_mode mode; + u16 fan_bitmap; + u8 fan, speed; + + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + fan = acer_wmi_fan_channel_to_fan_id[channel]; + speed = fixp_linear_interpolate(0, 0, U8_MAX, 100, + clamp_val(val, 0, U8_MAX)); + + return WMID_gaming_set_gaming_fan_speed(fan, speed); + case hwmon_pwm_enable: + fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel]; + + switch (val) { + case 0: + mode = ACER_WMID_FAN_MODE_TURBO; + break; + case 1: + mode = ACER_WMID_FAN_MODE_CUSTOM; + break; + case 2: + mode = ACER_WMID_FAN_MODE_AUTO; + break; + default: + return -EINVAL; + } + + return WMID_gaming_set_fan_behavior(fan_bitmap, mode); + default: + return -EOPNOTSUPP; + } default: return -EOPNOTSUPP; } @@ -2835,11 +3074,16 @@ static const struct hwmon_channel_info *const acer_wmi_hwmon_info[] = { HWMON_F_INPUT, HWMON_F_INPUT ), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE + ), NULL }; static const struct hwmon_ops acer_wmi_hwmon_ops = { .read = acer_wmi_hwmon_read, + .write = acer_wmi_hwmon_write, .is_visible = acer_wmi_hwmon_is_visible, }; diff --git a/drivers/platform/x86/amd/hfi/hfi.c b/drivers/platform/x86/amd/hfi/hfi.c index a465ac6f607e..83863a5e0fbc 100644 --- a/drivers/platform/x86/amd/hfi/hfi.c +++ b/drivers/platform/x86/amd/hfi/hfi.c @@ -12,7 +12,6 @@ #include <linux/acpi.h> #include <linux/cpu.h> -#include <linux/cpumask.h> #include <linux/debugfs.h> #include <linux/gfp.h> #include <linux/init.h> @@ -95,7 +94,6 @@ struct amd_hfi_classes { * struct amd_hfi_cpuinfo - HFI workload class info per CPU * @cpu: CPU index * @apic_id: APIC id of the current CPU - * @cpus: mask of CPUs associated with amd_hfi_cpuinfo * @class_index: workload class ID index * @nr_class: max number of workload class supported * @ipcc_scores: ipcc scores for each class @@ -106,7 +104,6 @@ struct amd_hfi_classes { struct amd_hfi_cpuinfo { int cpu; u32 apic_id; - cpumask_var_t cpus; s16 class_index; u8 nr_class; int *ipcc_scores; @@ -295,11 +292,6 @@ static int amd_hfi_online(unsigned int cpu) guard(mutex)(&hfi_cpuinfo_lock); - if (!zalloc_cpumask_var(&hfi_info->cpus, GFP_KERNEL)) - return -ENOMEM; - - cpumask_set_cpu(cpu, hfi_info->cpus); - ret = amd_hfi_set_state(cpu, true); if (ret) pr_err("WCT enable failed for CPU %u\n", cpu); @@ -329,8 +321,6 @@ static int amd_hfi_offline(unsigned int cpu) if (ret) pr_err("WCT disable failed for CPU %u\n", cpu); - free_cpumask_var(hfi_info->cpus); - return ret; } @@ -515,7 +505,6 @@ static int amd_hfi_probe(struct platform_device *pdev) static struct platform_driver amd_hfi_driver = { .driver = { .name = AMD_HFI_DRIVER, - .owner = THIS_MODULE, .pm = &amd_hfi_pm_ops, .acpi_match_table = ACPI_PTR(amd_hfi_platform_match), }, diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c index d0b74d243ce4..97ed71593bdf 100644 --- a/drivers/platform/x86/amd/hsmp/acpi.c +++ b/drivers/platform/x86/amd/hsmp/acpi.c @@ -22,12 +22,11 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/sysfs.h> +#include <linux/topology.h> #include <linux/uuid.h> #include <uapi/asm-generic/errno-base.h> -#include <asm/amd/node.h> - #include "hsmp.h" #define DRIVER_NAME "hsmp_acpi" @@ -586,9 +585,9 @@ static int hsmp_acpi_probe(struct platform_device *pdev) return -ENOMEM; if (!hsmp_pdev->is_probed) { - hsmp_pdev->num_sockets = amd_num_nodes(); - if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_NUM_NODES) { - dev_err(&pdev->dev, "Wrong number of sockets\n"); + hsmp_pdev->num_sockets = topology_max_packages(); + if (!hsmp_pdev->num_sockets) { + dev_err(&pdev->dev, "No CPU sockets detected\n"); return -ENODEV; } diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c index a184922bba8d..faf15a8f74bb 100644 --- a/drivers/platform/x86/amd/pmf/auto-mode.c +++ b/drivers/platform/x86/amd/pmf/auto-mode.c @@ -114,14 +114,14 @@ static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx, { struct power_table_control *pwr_ctrl = &config_store.mode_set[idx].power_control; - amd_pmf_send_cmd(dev, SET_SPL, false, pwr_ctrl->spl, NULL); - amd_pmf_send_cmd(dev, SET_FPPT, false, pwr_ctrl->fppt, NULL); - amd_pmf_send_cmd(dev, SET_SPPT, false, pwr_ctrl->sppt, NULL); - amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL); - amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, + amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, pwr_ctrl->spl, NULL); + amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, pwr_ctrl->fppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, pwr_ctrl->sppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, pwr_ctrl->sppt_apu_only, NULL); + amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, pwr_ctrl->stt_min, NULL); + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD, fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_APU]), NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD, fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_HS2]), NULL); if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c index 207a0b33d8d3..5469fefb6001 100644 --- a/drivers/platform/x86/amd/pmf/cnqf.c +++ b/drivers/platform/x86/amd/pmf/cnqf.c @@ -76,14 +76,14 @@ static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx, pc = &config_store.mode_set[src][idx].power_control; - amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL); - amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL); - amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL); - amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL); - amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, + amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, pc->spl, NULL); + amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, pc->fppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, pc->sppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, pc->sppt_apu_only, NULL); + amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, pc->stt_min, NULL); + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD, fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_APU]), NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD, fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_HS2]), NULL); if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index bc544a4a5266..8fc293c9c538 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -131,7 +131,7 @@ static void amd_pmf_get_metrics(struct work_struct *work) /* Transfer table contents */ memset(dev->buf, 0, sizeof(dev->m_table)); - amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL); + amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL); memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table)); time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time; @@ -289,8 +289,8 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer) hi = phys_addr >> 32; low = phys_addr & GENMASK(31, 0); - amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL); - amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL); + amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, SET_CMD, hi, NULL); + amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, SET_CMD, low, NULL); return 0; } @@ -465,9 +465,17 @@ static int amd_pmf_probe(struct platform_device *pdev) if (!dev->regbase) return -ENOMEM; - mutex_init(&dev->lock); - mutex_init(&dev->update_mutex); - mutex_init(&dev->cb_mutex); + err = devm_mutex_init(dev->dev, &dev->lock); + if (err) + return err; + + err = devm_mutex_init(dev->dev, &dev->update_mutex); + if (err) + return err; + + err = devm_mutex_init(dev->dev, &dev->cb_mutex); + if (err) + return err; apmf_acpi_init(dev); platform_set_drvdata(pdev, dev); @@ -491,9 +499,6 @@ static void amd_pmf_remove(struct platform_device *pdev) amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD); apmf_acpi_deinit(dev); amd_pmf_dbgfs_unregister(dev); - mutex_destroy(&dev->lock); - mutex_destroy(&dev->update_mutex); - mutex_destroy(&dev->cb_mutex); } static const struct attribute_group *amd_pmf_driver_groups[] = { diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index bd19f2a6bc78..9144c8c3bbaf 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -119,6 +119,13 @@ struct cookie_header { #define APTS_MAX_STATES 16 #define CUSTOM_BIOS_INPUT_BITS GENMASK(16, 7) +#define BIOS_INPUTS_MAX 10 + +/* amd_pmf_send_cmd() set/get */ +#define SET_CMD false +#define GET_CMD true + +#define METRICS_TABLE_ID 7 typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data); @@ -204,7 +211,7 @@ struct apmf_sbios_req_v1 { u8 skin_temp_apu; u8 skin_temp_hs2; u8 enable_cnqf; - u32 custom_policy[10]; + u32 custom_policy[BIOS_INPUTS_MAX]; } __packed; struct apmf_sbios_req_v2 { @@ -216,7 +223,7 @@ struct apmf_sbios_req_v2 { u32 stt_min_limit; u8 skin_temp_apu; u8 skin_temp_hs2; - u32 custom_policy[10]; + u32 custom_policy[BIOS_INPUTS_MAX]; } __packed; struct apmf_fan_idx { @@ -243,12 +250,12 @@ struct smu_pmf_metrics_v2 { u16 vclk_freq; /* MHz */ u16 vcn_activity; /* VCN busy % [0-100] */ u16 vpeclk_freq; /* MHz */ - u16 ipuclk_freq; /* MHz */ - u16 ipu_busy[8]; /* NPU busy % [0-100] */ + u16 npuclk_freq; /* MHz */ + u16 npu_busy[8]; /* NPU busy % [0-100] */ u16 dram_reads; /* MB/sec */ u16 dram_writes; /* MB/sec */ u16 core_c0residency[16]; /* C0 residency % [0-100] */ - u16 ipu_power; /* mW */ + u16 npu_power; /* mW */ u32 apu_power; /* mW */ u32 gfx_power; /* mW */ u32 dgpu_power; /* mW */ @@ -257,9 +264,9 @@ struct smu_pmf_metrics_v2 { u32 filter_alpha_value; /* time constant [us] */ u32 metrics_counter; u16 memclk_freq; /* MHz */ - u16 mpipuclk_freq; /* MHz */ - u16 ipu_reads; /* MB/sec */ - u16 ipu_writes; /* MB/sec */ + u16 mpnpuclk_freq; /* MHz */ + u16 npu_reads; /* MB/sec */ + u16 npu_writes; /* MB/sec */ u32 throttle_residency_prochot; u32 throttle_residency_spl; u32 throttle_residency_fppt; @@ -355,7 +362,7 @@ enum power_modes_v2 { }; struct pmf_bios_inputs_prev { - u32 custom_bios_inputs[10]; + u32 custom_bios_inputs[BIOS_INPUTS_MAX]; }; struct amd_pmf_dev { @@ -451,7 +458,7 @@ struct os_power_slider { struct amd_pmf_notify_smart_pc_update { u16 size; u32 pending_req; - u32 custom_bios[10]; + u32 custom_bios[BIOS_INPUTS_MAX]; } __packed; struct fan_table_control { diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c index 85192c7536b8..0a37dc6a7950 100644 --- a/drivers/platform/x86/amd/pmf/spc.c +++ b/drivers/platform/x86/amd/pmf/spc.c @@ -202,7 +202,7 @@ static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_ta { /* Get the updated metrics table data */ memset(dev->buf, 0, dev->mtable_size); - amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL); + amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL); switch (dev->cpu_id) { case AMD_CPU_ID_PS: diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c index c28f3c5744c2..0b70a5153f46 100644 --- a/drivers/platform/x86/amd/pmf/sps.c +++ b/drivers/platform/x86/amd/pmf/sps.c @@ -192,15 +192,15 @@ static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev) static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx) { - amd_pmf_send_cmd(dev, SET_PMF_PPT, false, apts_config_store.val[idx].pmf_ppt, NULL); - amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false, + amd_pmf_send_cmd(dev, SET_PMF_PPT, SET_CMD, apts_config_store.val[idx].pmf_ppt, NULL); + amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, SET_CMD, apts_config_store.val[idx].ppt_pmf_apu_only, NULL); - amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, + amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, apts_config_store.val[idx].stt_min_limit, NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD, fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_apu), NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD, fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_hs2), NULL); } @@ -211,30 +211,30 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, int src = amd_pmf_get_power_source(); if (op == SLIDER_OP_SET) { - amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); - amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); - amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); - amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, + amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, config_store.prop[src][idx].spl, NULL); + amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, config_store.prop[src][idx].fppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, config_store.prop[src][idx].sppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, config_store.prop[src][idx].sppt_apu_only, NULL); - amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, + amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, config_store.prop[src][idx].stt_min, NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD, fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU]), NULL); - amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD, fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2]), NULL); } else if (op == SLIDER_OP_GET) { - amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); - amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); - amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); - amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, + amd_pmf_send_cmd(dev, GET_SPL, GET_CMD, ARG_NONE, &table->prop[src][idx].spl); + amd_pmf_send_cmd(dev, GET_FPPT, GET_CMD, ARG_NONE, &table->prop[src][idx].fppt); + amd_pmf_send_cmd(dev, GET_SPPT, GET_CMD, ARG_NONE, &table->prop[src][idx].sppt); + amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, GET_CMD, ARG_NONE, &table->prop[src][idx].sppt_apu_only); - amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, + amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, GET_CMD, ARG_NONE, &table->prop[src][idx].stt_min); - amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, + amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, GET_CMD, ARG_NONE, (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); - amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, + amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, GET_CMD, ARG_NONE, (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); } } diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c index 6e8116bef4f6..0abce76f89ff 100644 --- a/drivers/platform/x86/amd/pmf/tee-if.c +++ b/drivers/platform/x86/amd/pmf/tee-if.c @@ -73,17 +73,56 @@ static void amd_pmf_update_uevents(struct amd_pmf_dev *dev, u16 event) input_sync(dev->pmf_idev); } +static int amd_pmf_get_bios_output_idx(u32 action_idx) +{ + switch (action_idx) { + case PMF_POLICY_BIOS_OUTPUT_1: + return 0; + case PMF_POLICY_BIOS_OUTPUT_2: + return 1; + case PMF_POLICY_BIOS_OUTPUT_3: + return 2; + case PMF_POLICY_BIOS_OUTPUT_4: + return 3; + case PMF_POLICY_BIOS_OUTPUT_5: + return 4; + case PMF_POLICY_BIOS_OUTPUT_6: + return 5; + case PMF_POLICY_BIOS_OUTPUT_7: + return 6; + case PMF_POLICY_BIOS_OUTPUT_8: + return 7; + case PMF_POLICY_BIOS_OUTPUT_9: + return 8; + case PMF_POLICY_BIOS_OUTPUT_10: + return 9; + default: + return -EINVAL; + } +} + +static void amd_pmf_update_bios_output(struct amd_pmf_dev *pdev, struct ta_pmf_action *action) +{ + u32 bios_idx; + + bios_idx = amd_pmf_get_bios_output_idx(action->action_index); + + amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx); +} + static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out) { + struct ta_pmf_action *action; u32 val; int idx; for (idx = 0; idx < out->actions_count; idx++) { - val = out->actions_list[idx].value; - switch (out->actions_list[idx].action_index) { + action = &out->actions_list[idx]; + val = action->value; + switch (action->action_index) { case PMF_POLICY_SPL: if (dev->prev_data->spl != val) { - amd_pmf_send_cmd(dev, SET_SPL, false, val, NULL); + amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, val, NULL); dev_dbg(dev->dev, "update SPL: %u\n", val); dev->prev_data->spl = val; } @@ -91,7 +130,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_SPPT: if (dev->prev_data->sppt != val) { - amd_pmf_send_cmd(dev, SET_SPPT, false, val, NULL); + amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, val, NULL); dev_dbg(dev->dev, "update SPPT: %u\n", val); dev->prev_data->sppt = val; } @@ -99,7 +138,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_FPPT: if (dev->prev_data->fppt != val) { - amd_pmf_send_cmd(dev, SET_FPPT, false, val, NULL); + amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, val, NULL); dev_dbg(dev->dev, "update FPPT: %u\n", val); dev->prev_data->fppt = val; } @@ -107,7 +146,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_SPPT_APU_ONLY: if (dev->prev_data->sppt_apuonly != val) { - amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, val, NULL); + amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, val, NULL); dev_dbg(dev->dev, "update SPPT_APU_ONLY: %u\n", val); dev->prev_data->sppt_apuonly = val; } @@ -115,7 +154,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_STT_MIN: if (dev->prev_data->stt_minlimit != val) { - amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, val, NULL); + amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, val, NULL); dev_dbg(dev->dev, "update STT_MIN: %u\n", val); dev->prev_data->stt_minlimit = val; } @@ -123,7 +162,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_STT_SKINTEMP_APU: if (dev->prev_data->stt_skintemp_apu != val) { - amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD, fixp_q88_fromint(val), NULL); dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val); dev->prev_data->stt_skintemp_apu = val; @@ -132,7 +171,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_STT_SKINTEMP_HS2: if (dev->prev_data->stt_skintemp_hs2 != val) { - amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD, fixp_q88_fromint(val), NULL); dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val); dev->prev_data->stt_skintemp_hs2 = val; @@ -141,7 +180,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_P3T: if (dev->prev_data->p3t_limit != val) { - amd_pmf_send_cmd(dev, SET_P3T, false, val, NULL); + amd_pmf_send_cmd(dev, SET_P3T, SET_CMD, val, NULL); dev_dbg(dev->dev, "update P3T: %u\n", val); dev->prev_data->p3t_limit = val; } @@ -149,7 +188,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_PMF_PPT: if (dev->prev_data->pmf_ppt != val) { - amd_pmf_send_cmd(dev, SET_PMF_PPT, false, val, NULL); + amd_pmf_send_cmd(dev, SET_PMF_PPT, SET_CMD, val, NULL); dev_dbg(dev->dev, "update PMF PPT: %u\n", val); dev->prev_data->pmf_ppt = val; } @@ -157,7 +196,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ case PMF_POLICY_PMF_PPT_APU_ONLY: if (dev->prev_data->pmf_ppt_apu_only != val) { - amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false, val, NULL); + amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, SET_CMD, val, NULL); dev_dbg(dev->dev, "update PMF PPT APU ONLY: %u\n", val); dev->prev_data->pmf_ppt_apu_only = val; } @@ -183,43 +222,16 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ break; case PMF_POLICY_BIOS_OUTPUT_1: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(0), 0); - break; - case PMF_POLICY_BIOS_OUTPUT_2: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(1), 1); - break; - case PMF_POLICY_BIOS_OUTPUT_3: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(2), 2); - break; - case PMF_POLICY_BIOS_OUTPUT_4: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(3), 3); - break; - case PMF_POLICY_BIOS_OUTPUT_5: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(4), 4); - break; - case PMF_POLICY_BIOS_OUTPUT_6: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(5), 5); - break; - case PMF_POLICY_BIOS_OUTPUT_7: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(6), 6); - break; - case PMF_POLICY_BIOS_OUTPUT_8: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(7), 7); - break; - case PMF_POLICY_BIOS_OUTPUT_9: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(8), 8); - break; - case PMF_POLICY_BIOS_OUTPUT_10: - amd_pmf_smartpc_apply_bios_output(dev, val, BIT(9), 9); + amd_pmf_update_bios_output(dev, action); break; } } diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c new file mode 100644 index 000000000000..9c1a9ad42bc4 --- /dev/null +++ b/drivers/platform/x86/asus-armoury.c @@ -0,0 +1,1161 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Asus Armoury (WMI) attributes driver. + * + * This driver uses the fw_attributes class to expose various WMI functions + * that are present in many gaming and some non-gaming ASUS laptops. + * + * These typically don't fit anywhere else in the sysfs such as under LED class, + * hwmon or others, and are set in Windows using the ASUS Armoury Crate tool. + * + * Copyright(C) 2024 Luke Jones <luke@ljones.dev> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/acpi.h> +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/dmi.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/kmod.h> +#include <linux/kobject.h> +#include <linux/kstrtox.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pci.h> +#include <linux/platform_data/x86/asus-wmi.h> +#include <linux/printk.h> +#include <linux/power_supply.h> +#include <linux/sysfs.h> + +#include "asus-armoury.h" +#include "firmware_attributes_class.h" + +#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" + +#define ASUS_MINI_LED_MODE_MASK GENMASK(1, 0) +/* Standard modes for devices with only on/off */ +#define ASUS_MINI_LED_OFF 0x00 +#define ASUS_MINI_LED_ON 0x01 +/* Like "on" but the effect is more vibrant or brighter */ +#define ASUS_MINI_LED_STRONG_MODE 0x02 +/* New modes for devices with 3 mini-led mode types */ +#define ASUS_MINI_LED_2024_WEAK 0x00 +#define ASUS_MINI_LED_2024_STRONG 0x01 +#define ASUS_MINI_LED_2024_OFF 0x02 + +/* Power tunable attribute name defines */ +#define ATTR_PPT_PL1_SPL "ppt_pl1_spl" +#define ATTR_PPT_PL2_SPPT "ppt_pl2_sppt" +#define ATTR_PPT_PL3_FPPT "ppt_pl3_fppt" +#define ATTR_PPT_APU_SPPT "ppt_apu_sppt" +#define ATTR_PPT_PLATFORM_SPPT "ppt_platform_sppt" +#define ATTR_NV_DYNAMIC_BOOST "nv_dynamic_boost" +#define ATTR_NV_TEMP_TARGET "nv_temp_target" +#define ATTR_NV_BASE_TGP "nv_base_tgp" +#define ATTR_NV_TGP "nv_tgp" + +#define ASUS_ROG_TUNABLE_DC 0 +#define ASUS_ROG_TUNABLE_AC 1 + +struct rog_tunables { + const struct power_limits *power_limits; + u32 ppt_pl1_spl; // cpu + u32 ppt_pl2_sppt; // cpu + u32 ppt_pl3_fppt; // cpu + u32 ppt_apu_sppt; // plat + u32 ppt_platform_sppt; // plat + + u32 nv_dynamic_boost; + u32 nv_temp_target; + u32 nv_tgp; +}; + +struct asus_armoury_priv { + struct device *fw_attr_dev; + struct kset *fw_attr_kset; + + /* + * Mutex to protect eGPU activation/deactivation + * sequences and dGPU connection status: + * do not allow concurrent changes or changes + * before a reboot if dGPU got disabled. + */ + struct mutex egpu_mutex; + + /* Index 0 for DC, 1 for AC */ + struct rog_tunables *rog_tunables[2]; + + u32 mini_led_dev_id; + u32 gpu_mux_dev_id; +}; + +static struct asus_armoury_priv asus_armoury = { + .egpu_mutex = __MUTEX_INITIALIZER(asus_armoury.egpu_mutex), +}; + +struct fw_attrs_group { + bool pending_reboot; +}; + +static struct fw_attrs_group fw_attrs = { + .pending_reboot = false, +}; + +struct asus_attr_group { + const struct attribute_group *attr_group; + u32 wmi_devid; +}; + +static void asus_set_reboot_and_signal_event(void) +{ + fw_attrs.pending_reboot = true; + kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE); +} + +static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot); +} + +static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); + +static bool asus_bios_requires_reboot(struct kobj_attribute *attr) +{ + return !strcmp(attr->attr.name, "gpu_mux_mode") || + !strcmp(attr->attr.name, "panel_hd_mode"); +} + +/** + * armoury_has_devstate() - Check presence of the WMI function state. + * + * @dev_id: The WMI method ID to check for presence. + * + * Returns: true iif method is supported. + */ +static bool armoury_has_devstate(u32 dev_id) +{ + u32 retval; + int status; + + status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval); + pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); + + return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); +} + +/** + * armoury_get_devstate() - Get the WMI function state. + * @attr: NULL or the kobj_attribute associated to called WMI function. + * @dev_id: The WMI method ID to call. + * @retval: + * * non-NULL pointer to where to store the value returned from WMI + * * with the function presence bit cleared. + * + * Intended usage is from sysfs attribute checking associated WMI function. + * + * Returns: + * * %-ENODEV - method ID is unsupported. + * * %0 - successful and retval is filled. + * * %other - error from WMI call. + */ +static int armoury_get_devstate(struct kobj_attribute *attr, u32 *retval, u32 dev_id) +{ + int err; + + err = asus_wmi_get_devstate_dsts(dev_id, retval); + if (err) { + if (attr) + pr_err("Failed to get %s: %d\n", attr->attr.name, err); + else + pr_err("Failed to get devstate for 0x%x: %d\n", dev_id, err); + + return err; + } + + /* + * asus_wmi_get_devstate_dsts will populate retval with WMI return, but + * the true value is expressed when ASUS_WMI_DSTS_PRESENCE_BIT is clear. + */ + *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT; + + return 0; +} + +/** + * armoury_set_devstate() - Set the WMI function state. + * @attr: The kobj_attribute associated to called WMI function. + * @dev_id: The WMI method ID to call. + * @value: The new value to be set. + * @retval: Where to store the value returned from WMI or NULL. + * + * Intended usage is from sysfs attribute setting associated WMI function. + * Before calling the presence of the function should be checked. + * + * Every WMI write MUST go through this function to enforce safety checks. + * + * Results !1 is usually considered a fail by ASUS, but some WMI methods + * (like eGPU or CPU cores) do use > 1 to return a status code or similar: + * in these cases caller is interested in the actual return value + * and should perform relevant checks. + * + * Returns: + * * %-EINVAL - attempt to set a dangerous or unsupported value. + * * %-EIO - WMI function returned an error. + * * %0 - successful and retval is filled. + * * %other - error from WMI call. + */ +static int armoury_set_devstate(struct kobj_attribute *attr, + u32 value, u32 *retval, u32 dev_id) +{ + u32 result; + int err; + + /* + * Prevent developers from bricking devices or issuing dangerous + * commands that can be difficult or impossible to recover from. + */ + switch (dev_id) { + case ASUS_WMI_DEVID_APU_MEM: + /* + * A hard reset might suffice to save the device, + * but there is no value in sending these commands. + */ + if (value == 0x100 || value == 0x101) { + pr_err("Refusing to set APU memory to unsafe value: 0x%x\n", value); + return -EINVAL; + } + break; + default: + /* No problems are known for this dev_id */ + break; + } + + err = asus_wmi_set_devstate(dev_id, value, retval ? retval : &result); + if (err) { + if (attr) + pr_err("Failed to set %s: %d\n", attr->attr.name, err); + else + pr_err("Failed to set devstate for 0x%x: %d\n", dev_id, err); + + return err; + } + + /* + * If retval == NULL caller is uninterested in return value: + * perform the most common result check here. + */ + if ((retval == NULL) && (result == 0)) { + pr_err("Failed to set %s: (result): 0x%x\n", attr->attr.name, result); + return -EIO; + } + + return 0; +} + +static int armoury_attr_enum_list(char *buf, size_t enum_values) +{ + size_t i; + int len = 0; + + for (i = 0; i < enum_values; i++) { + if (i == 0) + len += sysfs_emit_at(buf, len, "%zu", i); + else + len += sysfs_emit_at(buf, len, ";%zu", i); + } + len += sysfs_emit_at(buf, len, "\n"); + + return len; +} + +ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count, u32 min, u32 max, + u32 *store_value, u32 wmi_dev) +{ + u32 value; + int err; + + err = kstrtou32(buf, 10, &value); + if (err) + return err; + + if (value < min || value > max) + return -EINVAL; + + err = armoury_set_devstate(attr, value, NULL, wmi_dev); + if (err) + return err; + + if (store_value != NULL) + *store_value = value; + sysfs_notify(kobj, NULL, attr->attr.name); + + if (asus_bios_requires_reboot(attr)) + asus_set_reboot_and_signal_event(); + + return count; +} + +ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf, u32 wmi_dev) +{ + u32 result; + int err; + + err = armoury_get_devstate(attr, &result, wmi_dev); + if (err) + return err; + + return sysfs_emit(buf, "%u\n", result); +} + +static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "enumeration\n"); +} + +static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "integer\n"); +} + +/* Mini-LED mode **************************************************************/ + +/* Values map for mini-led modes on 2023 and earlier models. */ +static u32 mini_led_mode1_map[] = { + [0] = ASUS_MINI_LED_OFF, + [1] = ASUS_MINI_LED_ON, +}; + +/* Values map for mini-led modes on 2024 and later models. */ +static u32 mini_led_mode2_map[] = { + [0] = ASUS_MINI_LED_2024_OFF, + [1] = ASUS_MINI_LED_2024_WEAK, + [2] = ASUS_MINI_LED_2024_STRONG, +}; + +static ssize_t mini_led_mode_current_value_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + u32 *mini_led_mode_map; + size_t mini_led_mode_map_size; + u32 i, mode; + int err; + + switch (asus_armoury.mini_led_dev_id) { + case ASUS_WMI_DEVID_MINI_LED_MODE: + mini_led_mode_map = mini_led_mode1_map; + mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); + break; + + case ASUS_WMI_DEVID_MINI_LED_MODE2: + mini_led_mode_map = mini_led_mode2_map; + mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); + break; + + default: + pr_err("Unrecognized mini-LED device: %u\n", asus_armoury.mini_led_dev_id); + return -ENODEV; + } + + err = armoury_get_devstate(attr, &mode, asus_armoury.mini_led_dev_id); + if (err) + return err; + + mode = FIELD_GET(ASUS_MINI_LED_MODE_MASK, 0); + + for (i = 0; i < mini_led_mode_map_size; i++) + if (mode == mini_led_mode_map[i]) + return sysfs_emit(buf, "%u\n", i); + + pr_warn("Unrecognized mini-LED mode: %u", mode); + return -EINVAL; +} + +static ssize_t mini_led_mode_current_value_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + u32 *mini_led_mode_map; + size_t mini_led_mode_map_size; + u32 mode; + int err; + + err = kstrtou32(buf, 10, &mode); + if (err) + return err; + + switch (asus_armoury.mini_led_dev_id) { + case ASUS_WMI_DEVID_MINI_LED_MODE: + mini_led_mode_map = mini_led_mode1_map; + mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); + break; + + case ASUS_WMI_DEVID_MINI_LED_MODE2: + mini_led_mode_map = mini_led_mode2_map; + mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); + break; + + default: + pr_err("Unrecognized mini-LED devid: %u\n", asus_armoury.mini_led_dev_id); + return -EINVAL; + } + + if (mode >= mini_led_mode_map_size) { + pr_warn("mini-LED mode unrecognized device: %u\n", mode); + return -ENODEV; + } + + return armoury_attr_uint_store(kobj, attr, buf, count, + 0, mini_led_mode_map[mode], + NULL, asus_armoury.mini_led_dev_id); +} + +static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + switch (asus_armoury.mini_led_dev_id) { + case ASUS_WMI_DEVID_MINI_LED_MODE: + return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode1_map)); + case ASUS_WMI_DEVID_MINI_LED_MODE2: + return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode2_map)); + default: + return -ENODEV; + } +} +ASUS_ATTR_GROUP_ENUM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode"); + +static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int result, err; + bool optimus; + + err = kstrtobool(buf, &optimus); + if (err) + return err; + + if (armoury_has_devstate(ASUS_WMI_DEVID_DGPU)) { + err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_DGPU); + if (err) + return err; + if (result && !optimus) { + pr_warn("Cannot switch MUX to dGPU mode when dGPU is disabled: %02X\n", + result); + return -ENODEV; + } + } + + if (armoury_has_devstate(ASUS_WMI_DEVID_EGPU)) { + err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU); + if (err) + return err; + if (result && !optimus) { + pr_warn("Cannot switch MUX to dGPU mode when eGPU is enabled\n"); + return -EBUSY; + } + } + + err = armoury_set_devstate(attr, optimus ? 1 : 0, NULL, asus_armoury.gpu_mux_dev_id); + if (err) + return err; + + sysfs_notify(kobj, NULL, attr->attr.name); + asus_set_reboot_and_signal_event(); + + return count; +} +ASUS_WMI_SHOW_INT(gpu_mux_mode_current_value, asus_armoury.gpu_mux_dev_id); +ASUS_ATTR_GROUP_BOOL(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode"); + +static ssize_t dgpu_disable_current_value_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + int result, err; + bool disable; + + err = kstrtobool(buf, &disable); + if (err) + return err; + + if (asus_armoury.gpu_mux_dev_id) { + err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); + if (err) + return err; + if (!result && disable) { + pr_warn("Cannot disable dGPU when the MUX is in dGPU mode\n"); + return -EBUSY; + } + } + + scoped_guard(mutex, &asus_armoury.egpu_mutex) { + err = armoury_set_devstate(attr, disable ? 1 : 0, NULL, ASUS_WMI_DEVID_DGPU); + if (err) + return err; + } + + sysfs_notify(kobj, NULL, attr->attr.name); + + return count; +} +ASUS_WMI_SHOW_INT(dgpu_disable_current_value, ASUS_WMI_DEVID_DGPU); +ASUS_ATTR_GROUP_BOOL(dgpu_disable, "dgpu_disable", "Disable the dGPU"); + +/* Values map for eGPU activation requests. */ +static u32 egpu_status_map[] = { + [0] = 0x00000000U, + [1] = 0x00000001U, + [2] = 0x00000101U, + [3] = 0x00000201U, +}; + +/* + * armoury_pci_rescan() - Performs a PCI rescan + * + * Bring up any GPU that has been hotplugged in the system. + */ +static void armoury_pci_rescan(void) +{ + struct pci_bus *b = NULL; + + pci_lock_rescan_remove(); + while ((b = pci_find_next_bus(b)) != NULL) + pci_rescan_bus(b); + pci_unlock_rescan_remove(); +} + +/* + * The ACPI call to enable the eGPU might also disable the internal dGPU, + * but this is not always the case and on certain models enabling the eGPU + * when the dGPU is either still active or has been disabled without rebooting + * will make both GPUs malfunction and the kernel will detect many + * PCI AER unrecoverable errors. + */ +static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int err; + u32 requested, enable, result; + + err = kstrtou32(buf, 10, &requested); + if (err) + return err; + + if (requested >= ARRAY_SIZE(egpu_status_map)) + return -EINVAL; + enable = egpu_status_map[requested]; + + scoped_guard(mutex, &asus_armoury.egpu_mutex) { + /* Ensure the eGPU is connected before attempting to activate it. */ + if (enable) { + err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU_CONNECTED); + if (err) { + pr_warn("Failed to get eGPU connection status: %d\n", err); + return err; + } + if (!result) { + pr_warn("Cannot activate eGPU while undetected\n"); + return -ENOENT; + } + } + + if (asus_armoury.gpu_mux_dev_id) { + err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); + if (err) + return err; + + if (!result && enable) { + pr_warn("Cannot enable eGPU when the MUX is in dGPU mode\n"); + return -ENODEV; + } + } + + err = armoury_set_devstate(attr, enable, &result, ASUS_WMI_DEVID_EGPU); + if (err) { + pr_err("Failed to set %s: %d\n", attr->attr.name, err); + return err; + } + + /* + * ACPI returns value 0x01 on success and 0x02 on a partial activation: + * performing a pci rescan will bring up the device in pci-e 3.0 speed, + * after a reboot the device will work at full speed. + */ + switch (result) { + case 0x01: + /* + * When a GPU is in use it does not get disconnected even if + * the ACPI call returns a success. + */ + if (!enable) { + err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_EGPU); + if (err) { + pr_warn("Failed to ensure eGPU is deactivated: %d\n", err); + return err; + } + + if (result != 0) + return -EBUSY; + } + + pr_debug("Success changing the eGPU status\n"); + break; + case 0x02: + pr_info("Success changing the eGPU status, a reboot is strongly advised\n"); + asus_set_reboot_and_signal_event(); + break; + default: + pr_err("Failed to change the eGPU status: wmi result is 0x%x\n", result); + return -EIO; + } + } + + /* + * Perform a PCI rescan: on every tested model this is necessary + * to make the eGPU visible on the bus without rebooting. + */ + armoury_pci_rescan(); + + sysfs_notify(kobj, NULL, attr->attr.name); + + return count; +} + +static ssize_t egpu_enable_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int i, err; + u32 status; + + scoped_guard(mutex, &asus_armoury.egpu_mutex) { + err = armoury_get_devstate(attr, &status, ASUS_WMI_DEVID_EGPU); + if (err) + return err; + } + + for (i = 0; i < ARRAY_SIZE(egpu_status_map); i++) { + if (egpu_status_map[i] == status) + return sysfs_emit(buf, "%u\n", i); + } + + return -EIO; +} + +static ssize_t egpu_enable_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return armoury_attr_enum_list(buf, ARRAY_SIZE(egpu_status_map)); +} +ASUS_ATTR_GROUP_ENUM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)"); + +/* Device memory available to APU */ + +/* + * Values map for APU reserved memory (index + 1 number of GB). + * Some looks out of order, but are actually correct. + */ +static u32 apu_mem_map[] = { + [0] = 0x000, /* called "AUTO" on the BIOS, is the minimum available */ + [1] = 0x102, + [2] = 0x103, + [3] = 0x104, + [4] = 0x105, + [5] = 0x107, + [6] = 0x108, + [7] = 0x109, + [8] = 0x106, +}; + +static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int err; + u32 mem; + + err = armoury_get_devstate(attr, &mem, ASUS_WMI_DEVID_APU_MEM); + if (err) + return err; + + /* After 0x000 is set, a read will return 0x100 */ + if (mem == 0x100) + return sysfs_emit(buf, "0\n"); + + for (unsigned int i = 0; i < ARRAY_SIZE(apu_mem_map); i++) { + if (apu_mem_map[i] == mem) + return sysfs_emit(buf, "%u\n", i); + } + + pr_warn("Unrecognised value for APU mem 0x%08x\n", mem); + return -EIO; +} + +static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int result, err; + u32 requested, mem; + + result = kstrtou32(buf, 10, &requested); + if (result) + return result; + + if (requested >= ARRAY_SIZE(apu_mem_map)) + return -EINVAL; + mem = apu_mem_map[requested]; + + err = armoury_set_devstate(attr, mem, NULL, ASUS_WMI_DEVID_APU_MEM); + if (err) { + pr_warn("Failed to set apu_mem 0x%x: %d\n", mem, err); + return err; + } + + pr_info("APU memory changed to %uGB, reboot required\n", requested + 1); + sysfs_notify(kobj, NULL, attr->attr.name); + + asus_set_reboot_and_signal_event(); + + return count; +} + +static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return armoury_attr_enum_list(buf, ARRAY_SIZE(apu_mem_map)); +} +ASUS_ATTR_GROUP_ENUM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use"); + +/* Define helper to access the current power mode tunable values */ +static inline struct rog_tunables *get_current_tunables(void) +{ + if (power_supply_is_system_supplied()) + return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; + + return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]; +} + +/* Simple attribute creation */ +ASUS_ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2\n", + "Show the current mode of charging"); +ASUS_ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND, + "Set the boot POST sound"); +ASUS_ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, + "Set MCU powersaving mode"); +ASUS_ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD, + "Set the panel refresh overdrive"); +ASUS_ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD, + "Set the panel HD mode to UHD<0> or FHD<1>"); +ASUS_ATTR_GROUP_BOOL_RW(screen_auto_brightness, "screen_auto_brightness", + ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS, + "Set the panel brightness to Off<0> or On<1>"); +ASUS_ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, + "Show the eGPU connection status"); +ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, ATTR_PPT_PL1_SPL, ASUS_WMI_DEVID_PPT_PL1_SPL, + "Set the CPU slow package limit"); +ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, ATTR_PPT_PL2_SPPT, ASUS_WMI_DEVID_PPT_PL2_SPPT, + "Set the CPU fast package limit"); +ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl3_fppt, ATTR_PPT_PL3_FPPT, ASUS_WMI_DEVID_PPT_PL3_FPPT, + "Set the CPU fastest package limit"); +ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, ATTR_PPT_APU_SPPT, ASUS_WMI_DEVID_PPT_APU_SPPT, + "Set the APU package limit"); +ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, ATTR_PPT_PLATFORM_SPPT, ASUS_WMI_DEVID_PPT_PLAT_SPPT, + "Set the platform package limit"); +ASUS_ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, ATTR_NV_DYNAMIC_BOOST, ASUS_WMI_DEVID_NV_DYN_BOOST, + "Set the Nvidia dynamic boost limit"); +ASUS_ATTR_GROUP_ROG_TUNABLE(nv_temp_target, ATTR_NV_TEMP_TARGET, ASUS_WMI_DEVID_NV_THERM_TARGET, + "Set the Nvidia max thermal limit"); +ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, + "Set the additional TGP on top of the base TGP"); +ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, + "Read the base TGP value"); + +/* If an attribute does not require any special case handling add it here */ +static const struct asus_attr_group armoury_attr_groups[] = { + { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, + { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU }, + { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU }, + { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM }, + + { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, + { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, + { &ppt_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_PL3_FPPT }, + { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, + { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, + { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, + { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, + { &nv_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, + { &nv_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, + + { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, + { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, + { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE }, + { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD }, + { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD }, + { &screen_auto_brightness_attr_group, ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS }, +}; + +/** + * is_power_tunable_attr - Determines if an attribute is a power-related tunable + * @name: The name of the attribute to check + * + * This function checks if the given attribute name is related to power tuning. + * + * Return: true if the attribute is a power-related tunable, false otherwise + */ +static bool is_power_tunable_attr(const char *name) +{ + static const char * const power_tunable_attrs[] = { + ATTR_PPT_PL1_SPL, ATTR_PPT_PL2_SPPT, + ATTR_PPT_PL3_FPPT, ATTR_PPT_APU_SPPT, + ATTR_PPT_PLATFORM_SPPT, ATTR_NV_DYNAMIC_BOOST, + ATTR_NV_TEMP_TARGET, ATTR_NV_BASE_TGP, + ATTR_NV_TGP + }; + + for (unsigned int i = 0; i < ARRAY_SIZE(power_tunable_attrs); i++) { + if (!strcmp(name, power_tunable_attrs[i])) + return true; + } + + return false; +} + +/** + * has_valid_limit - Checks if a power-related attribute has a valid limit value + * @name: The name of the attribute to check + * @limits: Pointer to the power_limits structure containing limit values + * + * This function checks if a power-related attribute has a valid limit value. + * It returns false if limits is NULL or if the corresponding limit value is zero. + * + * Return: true if the attribute has a valid limit value, false otherwise + */ +static bool has_valid_limit(const char *name, const struct power_limits *limits) +{ + u32 limit_value = 0; + + if (!limits) + return false; + + if (!strcmp(name, ATTR_PPT_PL1_SPL)) + limit_value = limits->ppt_pl1_spl_max; + else if (!strcmp(name, ATTR_PPT_PL2_SPPT)) + limit_value = limits->ppt_pl2_sppt_max; + else if (!strcmp(name, ATTR_PPT_PL3_FPPT)) + limit_value = limits->ppt_pl3_fppt_max; + else if (!strcmp(name, ATTR_PPT_APU_SPPT)) + limit_value = limits->ppt_apu_sppt_max; + else if (!strcmp(name, ATTR_PPT_PLATFORM_SPPT)) + limit_value = limits->ppt_platform_sppt_max; + else if (!strcmp(name, ATTR_NV_DYNAMIC_BOOST)) + limit_value = limits->nv_dynamic_boost_max; + else if (!strcmp(name, ATTR_NV_TEMP_TARGET)) + limit_value = limits->nv_temp_target_max; + else if (!strcmp(name, ATTR_NV_BASE_TGP) || + !strcmp(name, ATTR_NV_TGP)) + limit_value = limits->nv_tgp_max; + + return limit_value > 0; +} + +static int asus_fw_attr_add(void) +{ + const struct rog_tunables *const ac_rog_tunables = + asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; + const struct power_limits *limits; + bool should_create; + const char *name; + int err, i; + + asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), + NULL, "%s", DRIVER_NAME); + if (IS_ERR(asus_armoury.fw_attr_dev)) { + err = PTR_ERR(asus_armoury.fw_attr_dev); + goto fail_class_get; + } + + asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL, + &asus_armoury.fw_attr_dev->kobj); + if (!asus_armoury.fw_attr_kset) { + err = -ENOMEM; + goto err_destroy_classdev; + } + + err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); + if (err) { + pr_err("Failed to create sysfs level attributes\n"); + goto err_destroy_kset; + } + + asus_armoury.mini_led_dev_id = 0; + if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE)) + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; + else if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE2)) + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; + + if (asus_armoury.mini_led_dev_id) { + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, + &mini_led_mode_attr_group); + if (err) { + pr_err("Failed to create sysfs-group for mini_led\n"); + goto err_remove_file; + } + } + + asus_armoury.gpu_mux_dev_id = 0; + if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX)) + asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX; + else if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX_VIVO)) + asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO; + + if (asus_armoury.gpu_mux_dev_id) { + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, + &gpu_mux_mode_attr_group); + if (err) { + pr_err("Failed to create sysfs-group for gpu_mux\n"); + goto err_remove_mini_led_group; + } + } + + for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { + if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) + continue; + + /* Always create by default, unless PPT is not present */ + should_create = true; + name = armoury_attr_groups[i].attr_group->name; + + /* Check if this is a power-related tunable requiring limits */ + if (ac_rog_tunables && ac_rog_tunables->power_limits && + is_power_tunable_attr(name)) { + limits = ac_rog_tunables->power_limits; + /* Check only AC: if not present then DC won't be either */ + should_create = has_valid_limit(name, limits); + if (!should_create) + pr_debug("Missing max value for tunable %s\n", name); + } + + if (should_create) { + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, + armoury_attr_groups[i].attr_group); + if (err) { + pr_err("Failed to create sysfs-group for %s\n", + armoury_attr_groups[i].attr_group->name); + goto err_remove_groups; + } + } + } + + return 0; + +err_remove_groups: + while (i--) { + if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, + armoury_attr_groups[i].attr_group); + } + if (asus_armoury.gpu_mux_dev_id) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); +err_remove_mini_led_group: + if (asus_armoury.mini_led_dev_id) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); +err_remove_file: + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); +err_destroy_kset: + kset_unregister(asus_armoury.fw_attr_kset); +err_destroy_classdev: +fail_class_get: + device_destroy(&firmware_attributes_class, MKDEV(0, 0)); + return err; +} + +/* Init / exit ****************************************************************/ + +/* Set up the min/max and defaults for ROG tunables */ +static void init_rog_tunables(void) +{ + const struct power_limits *ac_limits, *dc_limits; + struct rog_tunables *ac_rog_tunables = NULL, *dc_rog_tunables = NULL; + const struct power_data *power_data; + const struct dmi_system_id *dmi_id; + + /* Match the system against the power_limits table */ + dmi_id = dmi_first_match(power_limits); + if (!dmi_id) { + pr_warn("No matching power limits found for this system\n"); + return; + } + + /* Get the power data for this system */ + power_data = dmi_id->driver_data; + if (!power_data) { + pr_info("No power data available for this system\n"); + return; + } + + /* Initialize AC power tunables */ + ac_limits = power_data->ac_data; + if (ac_limits) { + ac_rog_tunables = kzalloc(sizeof(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]), + GFP_KERNEL); + if (!ac_rog_tunables) + goto err_nomem; + + asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables; + ac_rog_tunables->power_limits = ac_limits; + + /* Set initial AC values */ + ac_rog_tunables->ppt_pl1_spl = + ac_limits->ppt_pl1_spl_def ? + ac_limits->ppt_pl1_spl_def : + ac_limits->ppt_pl1_spl_max; + + ac_rog_tunables->ppt_pl2_sppt = + ac_limits->ppt_pl2_sppt_def ? + ac_limits->ppt_pl2_sppt_def : + ac_limits->ppt_pl2_sppt_max; + + ac_rog_tunables->ppt_pl3_fppt = + ac_limits->ppt_pl3_fppt_def ? + ac_limits->ppt_pl3_fppt_def : + ac_limits->ppt_pl3_fppt_max; + + ac_rog_tunables->ppt_apu_sppt = + ac_limits->ppt_apu_sppt_def ? + ac_limits->ppt_apu_sppt_def : + ac_limits->ppt_apu_sppt_max; + + ac_rog_tunables->ppt_platform_sppt = + ac_limits->ppt_platform_sppt_def ? + ac_limits->ppt_platform_sppt_def : + ac_limits->ppt_platform_sppt_max; + + ac_rog_tunables->nv_dynamic_boost = + ac_limits->nv_dynamic_boost_max; + ac_rog_tunables->nv_temp_target = + ac_limits->nv_temp_target_max; + ac_rog_tunables->nv_tgp = ac_limits->nv_tgp_max; + + pr_debug("AC power limits initialized for %s\n", dmi_id->matches[0].substr); + } else { + pr_debug("No AC PPT limits defined\n"); + } + + /* Initialize DC power tunables */ + dc_limits = power_data->dc_data; + if (dc_limits) { + dc_rog_tunables = kzalloc(sizeof(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]), + GFP_KERNEL); + if (!dc_rog_tunables) { + kfree(ac_rog_tunables); + goto err_nomem; + } + + asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables; + dc_rog_tunables->power_limits = dc_limits; + + /* Set initial DC values */ + dc_rog_tunables->ppt_pl1_spl = + dc_limits->ppt_pl1_spl_def ? + dc_limits->ppt_pl1_spl_def : + dc_limits->ppt_pl1_spl_max; + + dc_rog_tunables->ppt_pl2_sppt = + dc_limits->ppt_pl2_sppt_def ? + dc_limits->ppt_pl2_sppt_def : + dc_limits->ppt_pl2_sppt_max; + + dc_rog_tunables->ppt_pl3_fppt = + dc_limits->ppt_pl3_fppt_def ? + dc_limits->ppt_pl3_fppt_def : + dc_limits->ppt_pl3_fppt_max; + + dc_rog_tunables->ppt_apu_sppt = + dc_limits->ppt_apu_sppt_def ? + dc_limits->ppt_apu_sppt_def : + dc_limits->ppt_apu_sppt_max; + + dc_rog_tunables->ppt_platform_sppt = + dc_limits->ppt_platform_sppt_def ? + dc_limits->ppt_platform_sppt_def : + dc_limits->ppt_platform_sppt_max; + + dc_rog_tunables->nv_dynamic_boost = + dc_limits->nv_dynamic_boost_max; + dc_rog_tunables->nv_temp_target = + dc_limits->nv_temp_target_max; + dc_rog_tunables->nv_tgp = dc_limits->nv_tgp_max; + + pr_debug("DC power limits initialized for %s\n", dmi_id->matches[0].substr); + } else { + pr_debug("No DC PPT limits defined\n"); + } + + return; + +err_nomem: + pr_err("Failed to allocate memory for tunables\n"); +} + +static int __init asus_fw_init(void) +{ + char *wmi_uid; + + wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); + if (!wmi_uid) + return -ENODEV; + + /* + * if equal to "ASUSWMI" then it's DCTS that can't be used for this + * driver, DSTS is required. + */ + if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) + return -ENODEV; + + init_rog_tunables(); + + /* Must always be last step to ensure data is available */ + return asus_fw_attr_add(); +} + +static void __exit asus_fw_exit(void) +{ + int i; + + for (i = ARRAY_SIZE(armoury_attr_groups) - 1; i >= 0; i--) { + if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, + armoury_attr_groups[i].attr_group); + } + + if (asus_armoury.gpu_mux_dev_id) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); + + if (asus_armoury.mini_led_dev_id) + sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); + + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); + kset_unregister(asus_armoury.fw_attr_kset); + device_destroy(&firmware_attributes_class, MKDEV(0, 0)); + + kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); + kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); +} + +module_init(asus_fw_init); +module_exit(asus_fw_exit); + +MODULE_IMPORT_NS("ASUS_WMI"); +MODULE_AUTHOR("Luke Jones <luke@ljones.dev>"); +MODULE_DESCRIPTION("ASUS BIOS Configuration Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID); diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h new file mode 100644 index 000000000000..a1bb2005c3f3 --- /dev/null +++ b/drivers/platform/x86/asus-armoury.h @@ -0,0 +1,1541 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Definitions for kernel modules using asus-armoury driver + * + * Copyright (c) 2024 Luke Jones <luke@ljones.dev> + */ + +#ifndef _ASUS_ARMOURY_H_ +#define _ASUS_ARMOURY_H_ + +#include <linux/dmi.h> +#include <linux/platform_device.h> +#include <linux/sysfs.h> +#include <linux/types.h> + +#define DRIVER_NAME "asus-armoury" + +/** + * armoury_attr_uint_store() - Send an uint to WMI method if within min/max. + * @kobj: Pointer to the driver object. + * @attr: Pointer to the attribute calling this function. + * @buf: The buffer to read from, this is parsed to `uint` type. + * @count: Required by sysfs attribute macros, pass in from the callee attr. + * @min: Minimum accepted value. Below this returns -EINVAL. + * @max: Maximum accepted value. Above this returns -EINVAL. + * @store_value: Pointer to where the parsed value should be stored. + * @wmi_dev: The WMI function ID to use. + * + * This function is intended to be generic so it can be called from any "_store" + * attribute which works only with integers. + * + * Integers to be sent to the WMI method is inclusive range checked and + * an error returned if out of range. + * + * If the value is valid and WMI is success then the sysfs attribute is notified + * and if asus_bios_requires_reboot() is true then reboot attribute + * is also notified. + * + * Returns: Either count, or an error. + */ +ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count, u32 min, u32 max, + u32 *store_value, u32 wmi_dev); + +/** + * armoury_attr_uint_show() - Receive an uint from a WMI method. + * @kobj: Pointer to the driver object. + * @attr: Pointer to the attribute calling this function. + * @buf: The buffer to write to, as an `uint` type. + * @wmi_dev: The WMI function ID to use. + * + * This function is intended to be generic so it can be called from any "_show" + * attribute which works only with integers. + * + * Returns: Either count, or an error. + */ +ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf, u32 wmi_dev); + +#define __ASUS_ATTR_RO(_func, _name) \ + { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = _func##_##_name##_show, \ + } + +#define __ASUS_ATTR_RO_AS(_name, _show) \ + { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = _show, \ + } + +#define __ASUS_ATTR_RW(_func, _name) \ + __ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store) + +#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \ + static ssize_t _attr##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + const char *buf, size_t count) \ + { \ + return armoury_attr_uint_store(kobj, attr, buf, count, _min, \ + _max, NULL, _wmi); \ + } + +#define ASUS_WMI_SHOW_INT(_attr, _wmi) \ + static ssize_t _attr##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ + { \ + return armoury_attr_uint_show(kobj, attr, buf, _wmi); \ + } + +/* Create functions and attributes for use in other macros or on their own */ + +/* Shows a formatted static variable */ +#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \ + static ssize_t _attrname##_##_prop##_show( \ + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ + { \ + return sysfs_emit(buf, _fmt, _val); \ + } \ + static struct kobj_attribute attr_##_attrname##_##_prop = \ + __ASUS_ATTR_RO(_attrname, _prop) + +#define __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname)\ + ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ + static struct kobj_attribute attr_##_attrname##_current_value = \ + __ASUS_ATTR_RO(_attrname, current_value); \ + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ + __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ + static struct kobj_attribute attr_##_attrname##_type = \ + __ASUS_ATTR_RO_AS(type, enum_type_show); \ + static struct attribute *_attrname##_attrs[] = { \ + &attr_##_attrname##_current_value.attr, \ + &attr_##_attrname##_display_name.attr, \ + &attr_##_attrname##_possible_values.attr, \ + &attr_##_attrname##_type.attr, \ + NULL \ + }; \ + static const struct attribute_group _attrname##_attr_group = { \ + .name = _fsname, .attrs = _attrname##_attrs \ + } + +#define __ATTR_RW_INT_GROUP_ENUM(_attrname, _minv, _maxv, _wmi, _fsname,\ + _possible, _dispname) \ + __WMI_STORE_INT(_attrname##_current_value, _minv, _maxv, _wmi); \ + ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ + static struct kobj_attribute attr_##_attrname##_current_value = \ + __ASUS_ATTR_RW(_attrname, current_value); \ + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ + __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ + static struct kobj_attribute attr_##_attrname##_type = \ + __ASUS_ATTR_RO_AS(type, enum_type_show); \ + static struct attribute *_attrname##_attrs[] = { \ + &attr_##_attrname##_current_value.attr, \ + &attr_##_attrname##_display_name.attr, \ + &attr_##_attrname##_possible_values.attr, \ + &attr_##_attrname##_type.attr, \ + NULL \ + }; \ + static const struct attribute_group _attrname##_attr_group = { \ + .name = _fsname, .attrs = _attrname##_attrs \ + } + +/* Boolean style enumeration, base macro. Requires adding show/store */ +#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \ + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ + __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ + static struct kobj_attribute attr_##_attrname##_type = \ + __ASUS_ATTR_RO_AS(type, enum_type_show); \ + static struct attribute *_attrname##_attrs[] = { \ + &attr_##_attrname##_current_value.attr, \ + &attr_##_attrname##_display_name.attr, \ + &attr_##_attrname##_possible_values.attr, \ + &attr_##_attrname##_type.attr, \ + NULL \ + }; \ + static const struct attribute_group _attrname##_attr_group = { \ + .name = _fsname, .attrs = _attrname##_attrs \ + } + +#define ASUS_ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \ + __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, "0;1", _dispname) + + +#define ASUS_ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \ + __ATTR_RW_INT_GROUP_ENUM(_attrname, 0, 1, _wmi, _fsname, "0;1", _dispname) + +#define ASUS_ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _possible, _dispname) \ + __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname) + +/* + * Requires <name>_current_value_show(), <name>_current_value_show() + */ +#define ASUS_ATTR_GROUP_BOOL(_attrname, _fsname, _dispname) \ + static struct kobj_attribute attr_##_attrname##_current_value = \ + __ASUS_ATTR_RW(_attrname, current_value); \ + __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) + +/* + * Requires <name>_current_value_show(), <name>_current_value_show() + * and <name>_possible_values_show() + */ +#define ASUS_ATTR_GROUP_ENUM(_attrname, _fsname, _dispname) \ + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ + static struct kobj_attribute attr_##_attrname##_current_value = \ + __ASUS_ATTR_RW(_attrname, current_value); \ + static struct kobj_attribute attr_##_attrname##_possible_values = \ + __ASUS_ATTR_RO(_attrname, possible_values); \ + static struct kobj_attribute attr_##_attrname##_type = \ + __ASUS_ATTR_RO_AS(type, enum_type_show); \ + static struct attribute *_attrname##_attrs[] = { \ + &attr_##_attrname##_current_value.attr, \ + &attr_##_attrname##_display_name.attr, \ + &attr_##_attrname##_possible_values.attr, \ + &attr_##_attrname##_type.attr, \ + NULL \ + }; \ + static const struct attribute_group _attrname##_attr_group = { \ + .name = _fsname, .attrs = _attrname##_attrs \ + } + +#define ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \ + ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ + static struct kobj_attribute attr_##_attrname##_current_value = \ + __ASUS_ATTR_RO(_attrname, current_value); \ + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ + static struct kobj_attribute attr_##_attrname##_type = \ + __ASUS_ATTR_RO_AS(type, int_type_show); \ + static struct attribute *_attrname##_attrs[] = { \ + &attr_##_attrname##_current_value.attr, \ + &attr_##_attrname##_display_name.attr, \ + &attr_##_attrname##_type.attr, NULL \ + }; \ + static const struct attribute_group _attrname##_attr_group = { \ + .name = _fsname, .attrs = _attrname##_attrs \ + } + +/* + * ROG PPT attributes need a little different in setup as they + * require rog_tunables members. + */ + +#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ + static ssize_t _attrname##_##_prop##_show( \ + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ + { \ + struct rog_tunables *tunables = get_current_tunables(); \ + \ + if (!tunables || !tunables->power_limits) \ + return -ENODEV; \ + \ + return sysfs_emit(buf, "%d\n", tunables->power_limits->_val); \ + } \ + static struct kobj_attribute attr_##_attrname##_##_prop = \ + __ASUS_ATTR_RO(_attrname, _prop) + +#define __ROG_TUNABLE_SHOW_DEFAULT(_attrname) \ + static ssize_t _attrname##_default_value_show( \ + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ + { \ + struct rog_tunables *tunables = get_current_tunables(); \ + \ + if (!tunables || !tunables->power_limits) \ + return -ENODEV; \ + \ + return sysfs_emit( \ + buf, "%d\n", \ + tunables->power_limits->_attrname##_def ? \ + tunables->power_limits->_attrname##_def : \ + tunables->power_limits->_attrname##_max); \ + } \ + static struct kobj_attribute attr_##_attrname##_default_value = \ + __ASUS_ATTR_RO(_attrname, default_value) + +#define __ROG_TUNABLE_RW(_attr, _wmi) \ + static ssize_t _attr##_current_value_store( \ + struct kobject *kobj, struct kobj_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct rog_tunables *tunables = get_current_tunables(); \ + \ + if (!tunables || !tunables->power_limits) \ + return -ENODEV; \ + \ + if (tunables->power_limits->_attr##_min == \ + tunables->power_limits->_attr##_max) \ + return -EINVAL; \ + \ + return armoury_attr_uint_store(kobj, attr, buf, count, \ + tunables->power_limits->_attr##_min, \ + tunables->power_limits->_attr##_max, \ + &tunables->_attr, _wmi); \ + } \ + static ssize_t _attr##_current_value_show( \ + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ + { \ + struct rog_tunables *tunables = get_current_tunables(); \ + \ + if (!tunables) \ + return -ENODEV; \ + \ + return sysfs_emit(buf, "%u\n", tunables->_attr); \ + } \ + static struct kobj_attribute attr_##_attr##_current_value = \ + __ASUS_ATTR_RW(_attr, current_value) + +#define ASUS_ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _dispname) \ + __ROG_TUNABLE_RW(_attrname, _wmi); \ + __ROG_TUNABLE_SHOW_DEFAULT(_attrname); \ + __ROG_TUNABLE_SHOW(min_value, _attrname, _attrname##_min); \ + __ROG_TUNABLE_SHOW(max_value, _attrname, _attrname##_max); \ + __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ + static struct kobj_attribute attr_##_attrname##_type = \ + __ASUS_ATTR_RO_AS(type, int_type_show); \ + static struct attribute *_attrname##_attrs[] = { \ + &attr_##_attrname##_current_value.attr, \ + &attr_##_attrname##_default_value.attr, \ + &attr_##_attrname##_min_value.attr, \ + &attr_##_attrname##_max_value.attr, \ + &attr_##_attrname##_scalar_increment.attr, \ + &attr_##_attrname##_display_name.attr, \ + &attr_##_attrname##_type.attr, \ + NULL \ + }; \ + static const struct attribute_group _attrname##_attr_group = { \ + .name = _fsname, .attrs = _attrname##_attrs \ + } + +/* Default is always the maximum value unless *_def is specified */ +struct power_limits { + u8 ppt_pl1_spl_min; + u8 ppt_pl1_spl_def; + u8 ppt_pl1_spl_max; + u8 ppt_pl2_sppt_min; + u8 ppt_pl2_sppt_def; + u8 ppt_pl2_sppt_max; + u8 ppt_pl3_fppt_min; + u8 ppt_pl3_fppt_def; + u8 ppt_pl3_fppt_max; + u8 ppt_apu_sppt_min; + u8 ppt_apu_sppt_def; + u8 ppt_apu_sppt_max; + u8 ppt_platform_sppt_min; + u8 ppt_platform_sppt_def; + u8 ppt_platform_sppt_max; + /* Nvidia GPU specific, default is always max */ + u8 nv_dynamic_boost_def; // unused. exists for macro + u8 nv_dynamic_boost_min; + u8 nv_dynamic_boost_max; + u8 nv_temp_target_def; // unused. exists for macro + u8 nv_temp_target_min; + u8 nv_temp_target_max; + u8 nv_tgp_def; // unused. exists for macro + u8 nv_tgp_min; + u8 nv_tgp_max; +}; + +struct power_data { + const struct power_limits *ac_data; + const struct power_limits *dc_data; + bool requires_fan_curve; +}; + +/* + * For each available attribute there must be a min and a max. + * _def is not required and will be assumed to be default == max if missing. + */ +static const struct dmi_system_id power_limits[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA401W"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 75, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 30, + .ppt_pl2_sppt_min = 31, + .ppt_pl2_sppt_max = 44, + .ppt_pl3_fppt_min = 45, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA507N"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA507UV"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 115, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA507R"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80 + }, + .dc_data = NULL, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA507X"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 85, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA507Z"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 105, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 15, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 85, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 45, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 60, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA607P"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_def = 100, + .ppt_pl1_spl_max = 135, + .ppt_pl2_sppt_min = 30, + .ppt_pl2_sppt_def = 115, + .ppt_pl2_sppt_max = 135, + .ppt_pl3_fppt_min = 30, + .ppt_pl3_fppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 115, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_def = 60, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 25, + .ppt_pl3_fppt_max = 80, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA608WI"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 90, + .ppt_pl1_spl_max = 90, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 90, + .ppt_pl2_sppt_max = 90, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 90, + .ppt_pl3_fppt_max = 90, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 115, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 65, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA617NS"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_apu_sppt_min = 15, + .ppt_apu_sppt_max = 80, + .ppt_platform_sppt_min = 30, + .ppt_platform_sppt_max = 120, + }, + .dc_data = &(struct power_limits) { + .ppt_apu_sppt_min = 25, + .ppt_apu_sppt_max = 35, + .ppt_platform_sppt_min = 45, + .ppt_platform_sppt_max = 100, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA617NT"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_apu_sppt_min = 15, + .ppt_apu_sppt_max = 80, + .ppt_platform_sppt_min = 30, + .ppt_platform_sppt_max = 115, + }, + .dc_data = &(struct power_limits) { + .ppt_apu_sppt_min = 15, + .ppt_apu_sppt_max = 45, + .ppt_platform_sppt_min = 30, + .ppt_platform_sppt_max = 50, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA617XS"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_apu_sppt_min = 15, + .ppt_apu_sppt_max = 80, + .ppt_platform_sppt_min = 30, + .ppt_platform_sppt_max = 120, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_apu_sppt_min = 25, + .ppt_apu_sppt_max = 35, + .ppt_platform_sppt_min = 45, + .ppt_platform_sppt_max = 100, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FX507VI"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 135, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 45, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 60, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FX507VV"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 115, + .ppt_pl1_spl_max = 135, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 45, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 60, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FX507Z"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 90, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 15, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 45, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 60, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA401Q"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 15, + .ppt_pl2_sppt_max = 80, + }, + .dc_data = NULL, + }, + }, + { + .matches = { + // This model is full AMD. No Nvidia dGPU. + DMI_MATCH(DMI_BOARD_NAME, "GA402R"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_apu_sppt_min = 15, + .ppt_apu_sppt_max = 80, + .ppt_platform_sppt_min = 30, + .ppt_platform_sppt_max = 115, + }, + .dc_data = &(struct power_limits) { + .ppt_apu_sppt_min = 25, + .ppt_apu_sppt_def = 30, + .ppt_apu_sppt_max = 45, + .ppt_platform_sppt_min = 40, + .ppt_platform_sppt_max = 60, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA402X"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 35, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_def = 65, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 35, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA403U"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 65, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 35, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA503QR"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 35, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 65, + .ppt_pl2_sppt_max = 80, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA503R"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 35, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 65, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 25, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 60, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA605W"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 85, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 31, + .ppt_pl2_sppt_max = 44, + .ppt_pl3_fppt_min = 45, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GU603Z"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 60, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 40, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 40, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + } + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GU604V"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 65, + .ppt_pl1_spl_max = 120, + .ppt_pl2_sppt_min = 65, + .ppt_pl2_sppt_max = 150, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 40, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 40, + .ppt_pl2_sppt_max = 60, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GU605CW"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 45, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 56, + .ppt_pl2_sppt_max = 110, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 80, + .nv_tgp_def = 90, + .nv_tgp_max = 110, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 32, + .ppt_pl2_sppt_max = 110, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GU605CX"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 45, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 56, + .ppt_pl2_sppt_max = 110, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 7, + .nv_temp_target_max = 87, + .nv_tgp_min = 95, + .nv_tgp_def = 100, + .nv_tgp_max = 110, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 32, + .ppt_pl2_sppt_max = 110, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GU605M"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 90, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 38, + .ppt_pl2_sppt_max = 53, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GV301Q"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 45, + .ppt_pl2_sppt_min = 65, + .ppt_pl2_sppt_max = 80, + }, + .dc_data = NULL, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GV301R"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 45, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 54, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 35, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GV601R"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 35, + .ppt_pl1_spl_max = 90, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 100, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 80, + .ppt_pl3_fppt_max = 125, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 28, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 60, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 80, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GV601V"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 100, + .ppt_pl1_spl_max = 110, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 40, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 40, + .ppt_pl2_sppt_max = 60, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GX650P"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 110, + .ppt_pl1_spl_max = 130, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 125, + .ppt_pl2_sppt_max = 130, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 125, + .ppt_pl3_fppt_max = 135, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 25, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 35, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 42, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G513I"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + /* Yes this laptop is very limited */ + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 15, + .ppt_pl2_sppt_max = 80, + }, + .dc_data = NULL, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G513QM"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + /* Yes this laptop is very limited */ + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 100, + .ppt_pl2_sppt_min = 15, + .ppt_pl2_sppt_max = 190, + }, + .dc_data = NULL, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G513R"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 35, + .ppt_pl1_spl_max = 90, + .ppt_pl2_sppt_min = 54, + .ppt_pl2_sppt_max = 100, + .ppt_pl3_fppt_min = 54, + .ppt_pl3_fppt_max = 125, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 50, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 50, + .ppt_pl3_fppt_min = 28, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G614J"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 140, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G634J"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 140, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G713PV"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_def = 120, + .ppt_pl1_spl_max = 130, + .ppt_pl2_sppt_min = 65, + .ppt_pl2_sppt_def = 125, + .ppt_pl2_sppt_max = 130, + .ppt_pl3_fppt_min = 65, + .ppt_pl3_fppt_def = 125, + .ppt_pl3_fppt_max = 130, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 75, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G733C"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 170, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 35, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G733P"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_def = 100, + .ppt_pl1_spl_max = 130, + .ppt_pl2_sppt_min = 65, + .ppt_pl2_sppt_def = 125, + .ppt_pl2_sppt_max = 130, + .ppt_pl3_fppt_min = 65, + .ppt_pl3_fppt_def = 125, + .ppt_pl3_fppt_max = 130, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 75, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G814J"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 140, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 140, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G834J"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_max = 140, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "H7606W"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 85, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 31, + .ppt_pl2_sppt_max = 44, + .ppt_pl3_fppt_min = 45, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "RC71"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 7, + .ppt_pl1_spl_max = 30, + .ppt_pl2_sppt_min = 15, + .ppt_pl2_sppt_max = 43, + .ppt_pl3_fppt_min = 15, + .ppt_pl3_fppt_max = 53, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 7, + .ppt_pl1_spl_def = 15, + .ppt_pl1_spl_max = 25, + .ppt_pl2_sppt_min = 15, + .ppt_pl2_sppt_def = 20, + .ppt_pl2_sppt_max = 30, + .ppt_pl3_fppt_min = 15, + .ppt_pl3_fppt_def = 25, + .ppt_pl3_fppt_max = 35, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "RC72"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 7, + .ppt_pl1_spl_max = 30, + .ppt_pl2_sppt_min = 15, + .ppt_pl2_sppt_max = 43, + .ppt_pl3_fppt_min = 15, + .ppt_pl3_fppt_max = 53, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 7, + .ppt_pl1_spl_def = 17, + .ppt_pl1_spl_max = 25, + .ppt_pl2_sppt_min = 15, + .ppt_pl2_sppt_def = 24, + .ppt_pl2_sppt_max = 30, + .ppt_pl3_fppt_min = 15, + .ppt_pl3_fppt_def = 30, + .ppt_pl3_fppt_max = 35, + }, + }, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "RC73XA"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 7, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 14, + .ppt_pl2_sppt_max = 45, + .ppt_pl3_fppt_min = 19, + .ppt_pl3_fppt_max = 55, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 7, + .ppt_pl1_spl_def = 17, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 13, + .ppt_pl2_sppt_def = 21, + .ppt_pl2_sppt_max = 45, + .ppt_pl3_fppt_min = 19, + .ppt_pl3_fppt_def = 26, + .ppt_pl3_fppt_max = 55, + }, + }, + }, + {} +}; + +#endif /* _ASUS_ARMOURY_H_ */ diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index e72a2b5d158e..4aec7ec69250 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -15,6 +15,7 @@ #include <linux/acpi.h> #include <linux/backlight.h> +#include <linux/bits.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dmi.h> @@ -30,6 +31,7 @@ #include <linux/pci.h> #include <linux/pci_hotplug.h> #include <linux/platform_data/x86/asus-wmi.h> +#include <linux/platform_data/x86/asus-wmi-leds-ids.h> #include <linux/platform_device.h> #include <linux/platform_profile.h> #include <linux/power_supply.h> @@ -55,8 +57,6 @@ module_param(fnlock_default, bool, 0444); #define to_asus_wmi_driver(pdrv) \ (container_of((pdrv), struct asus_wmi_driver, platform_driver)) -#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" - #define NOTIFY_BRNUP_MIN 0x11 #define NOTIFY_BRNUP_MAX 0x1f #define NOTIFY_BRNDOWN_MIN 0x20 @@ -105,8 +105,6 @@ module_param(fnlock_default, bool, 0444); #define USB_INTEL_XUSB2PR 0xD0 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 -#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI" - #define WMI_EVENT_MASK 0xFFFF #define FAN_CURVE_POINTS 8 @@ -340,6 +338,13 @@ struct asus_wmi { /* Global to allow setting externally without requiring driver data */ static enum asus_ally_mcu_hack use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_INIT; +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) +static void asus_wmi_show_deprecated(void) +{ + pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi is deprecated and will be removed in a future release. Please switch over to /sys/class/firmware_attributes.\n"); +} +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ + /* WMI ************************************************************************/ static int asus_wmi_evaluate_method3(u32 method_id, @@ -390,7 +395,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) { return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval); } -EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method); +EXPORT_SYMBOL_NS_GPL(asus_wmi_evaluate_method, "ASUS_WMI"); static int asus_wmi_evaluate_method5(u32 method_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval) @@ -554,12 +559,52 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) return 0; } -int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, - u32 *retval) +/** + * asus_wmi_get_devstate_dsts() - Get the WMI function state. + * @dev_id: The WMI method ID to call. + * @retval: A pointer to where to store the value returned from WMI. + * + * Returns: + * * %-ENODEV - method ID is unsupported. + * * %0 - successful and retval is filled. + * * %other - error from WMI call. + */ +int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval) +{ + int err; + + err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval); + if (err) + return err; + + if ((*retval & ASUS_WMI_DSTS_PRESENCE_BIT) == 0x00) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(asus_wmi_get_devstate_dsts, "ASUS_WMI"); + +/** + * asus_wmi_set_devstate() - Set the WMI function state. + * + * Note: an asus_wmi_set_devstate() call must be paired with a + * asus_wmi_get_devstate_dsts() to check if the WMI function is supported. + * + * @dev_id: The WMI function to call. + * @ctrl_param: The argument to be used for this WMI function. + * @retval: A pointer to where to store the value returned from WMI. + * + * Returns: + * * %-ENODEV - method ID is unsupported. + * * %0 - successful and retval is filled. + * * %other - error from WMI call. + */ +int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval) { return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval); } +EXPORT_SYMBOL_NS_GPL(asus_wmi_set_devstate, "ASUS_WMI"); /* Helper for special devices with magic return codes */ static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, @@ -692,6 +737,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) } /* Charging mode, 1=Barrel, 2=USB ******************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t charge_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -702,12 +748,16 @@ static ssize_t charge_mode_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", value & 0xff); } static DEVICE_ATTR_RO(charge_mode); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* dGPU ********************************************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t dgpu_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -718,6 +768,8 @@ static ssize_t dgpu_disable_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", result); } @@ -771,8 +823,10 @@ static ssize_t dgpu_disable_store(struct device *dev, return count; } static DEVICE_ATTR_RW(dgpu_disable); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* eGPU ********************************************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t egpu_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -783,6 +837,8 @@ static ssize_t egpu_enable_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", result); } @@ -839,8 +895,10 @@ static ssize_t egpu_enable_store(struct device *dev, return count; } static DEVICE_ATTR_RW(egpu_enable); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* Is eGPU connected? *********************************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t egpu_connected_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -851,12 +909,16 @@ static ssize_t egpu_connected_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", result); } static DEVICE_ATTR_RO(egpu_connected); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* gpu mux switch *************************************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t gpu_mux_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -867,6 +929,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", result); } @@ -925,6 +989,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev, return count; } static DEVICE_ATTR_RW(gpu_mux_mode); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* TUF Laptop Keyboard RGB Modes **********************************************/ static ssize_t kbd_rgb_mode_store(struct device *dev, @@ -1048,6 +1113,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = { }; /* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t ppt_pl2_sppt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1086,6 +1152,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt); } static DEVICE_ATTR_RW(ppt_pl2_sppt); @@ -1128,6 +1196,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl); } static DEVICE_ATTR_RW(ppt_pl1_spl); @@ -1148,7 +1218,7 @@ static ssize_t ppt_fppt_store(struct device *dev, if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) return -EINVAL; - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result); + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL3_FPPT, value, &result); if (err) { pr_warn("Failed to set ppt_fppt: %d\n", err); return err; @@ -1171,6 +1241,8 @@ static ssize_t ppt_fppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%u\n", asus->ppt_fppt); } static DEVICE_ATTR_RW(ppt_fppt); @@ -1214,6 +1286,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt); } static DEVICE_ATTR_RW(ppt_apu_sppt); @@ -1257,6 +1331,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt); } static DEVICE_ATTR_RW(ppt_platform_sppt); @@ -1300,6 +1376,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost); } static DEVICE_ATTR_RW(nv_dynamic_boost); @@ -1343,9 +1421,12 @@ static ssize_t nv_temp_target_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%u\n", asus->nv_temp_target); } static DEVICE_ATTR_RW(nv_temp_target); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* Ally MCU Powersave ********************************************************/ @@ -1386,6 +1467,7 @@ void set_ally_mcu_powersave(bool enabled) } EXPORT_SYMBOL_NS_GPL(set_ally_mcu_powersave, "ASUS_WMI"); +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t mcu_powersave_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1396,6 +1478,8 @@ static ssize_t mcu_powersave_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", result); } @@ -1431,6 +1515,7 @@ static ssize_t mcu_powersave_store(struct device *dev, return count; } static DEVICE_ATTR_RW(mcu_powersave); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* Battery ********************************************************************/ @@ -1619,14 +1704,14 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value) kbd_led_update(asus); } -static void kbd_led_set(struct led_classdev *led_cdev, - enum led_brightness value) +static int kbd_led_set(struct led_classdev *led_cdev, enum led_brightness value) { /* Prevent disabling keyboard backlight on module unregister */ if (led_cdev->flags & LED_UNREGISTERING) - return; + return 0; do_kbd_led_set(led_cdev, value); + return 0; } static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value) @@ -1802,7 +1887,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus) asus->kbd_led_wk = led_val; asus->kbd_led.name = "asus::kbd_backlight"; asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; - asus->kbd_led.brightness_set = kbd_led_set; + asus->kbd_led.brightness_set_blocking = kbd_led_set; asus->kbd_led.brightness_get = kbd_led_get; asus->kbd_led.max_brightness = 3; @@ -2304,6 +2389,7 @@ exit: } /* Panel Overdrive ************************************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t panel_od_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2314,6 +2400,8 @@ static ssize_t panel_od_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", result); } @@ -2350,9 +2438,10 @@ static ssize_t panel_od_store(struct device *dev, return count; } static DEVICE_ATTR_RW(panel_od); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* Bootup sound ***************************************************************/ - +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t boot_sound_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2363,6 +2452,8 @@ static ssize_t boot_sound_show(struct device *dev, if (result < 0) return result; + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", result); } @@ -2398,8 +2489,10 @@ static ssize_t boot_sound_store(struct device *dev, return count; } static DEVICE_ATTR_RW(boot_sound); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* Mini-LED mode **************************************************************/ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t mini_led_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2430,6 +2523,8 @@ static ssize_t mini_led_mode_show(struct device *dev, } } + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "%d\n", value); } @@ -2500,10 +2595,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev, return sysfs_emit(buf, "0 1 2\n"); } + asus_wmi_show_deprecated(); + return sysfs_emit(buf, "0\n"); } static DEVICE_ATTR_RO(available_mini_led_mode); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* Quirks *********************************************************************/ @@ -3791,6 +3889,7 @@ static int throttle_thermal_policy_set_default(struct asus_wmi *asus) return throttle_thermal_policy_write(asus); } +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static ssize_t throttle_thermal_policy_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3834,6 +3933,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent */ static DEVICE_ATTR_RW(throttle_thermal_policy); +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ /* Platform profile ***********************************************************/ static int asus_wmi_platform_profile_get(struct device *dev, @@ -4435,27 +4535,29 @@ static struct attribute *platform_attributes[] = { &dev_attr_camera.attr, &dev_attr_cardr.attr, &dev_attr_touchpad.attr, - &dev_attr_charge_mode.attr, - &dev_attr_egpu_enable.attr, - &dev_attr_egpu_connected.attr, - &dev_attr_dgpu_disable.attr, - &dev_attr_gpu_mux_mode.attr, &dev_attr_lid_resume.attr, &dev_attr_als_enable.attr, &dev_attr_fan_boost_mode.attr, - &dev_attr_throttle_thermal_policy.attr, - &dev_attr_ppt_pl2_sppt.attr, - &dev_attr_ppt_pl1_spl.attr, - &dev_attr_ppt_fppt.attr, - &dev_attr_ppt_apu_sppt.attr, - &dev_attr_ppt_platform_sppt.attr, - &dev_attr_nv_dynamic_boost.attr, - &dev_attr_nv_temp_target.attr, - &dev_attr_mcu_powersave.attr, - &dev_attr_boot_sound.attr, - &dev_attr_panel_od.attr, - &dev_attr_mini_led_mode.attr, - &dev_attr_available_mini_led_mode.attr, +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) + &dev_attr_charge_mode.attr, + &dev_attr_egpu_enable.attr, + &dev_attr_egpu_connected.attr, + &dev_attr_dgpu_disable.attr, + &dev_attr_gpu_mux_mode.attr, + &dev_attr_ppt_pl2_sppt.attr, + &dev_attr_ppt_pl1_spl.attr, + &dev_attr_ppt_fppt.attr, + &dev_attr_ppt_apu_sppt.attr, + &dev_attr_ppt_platform_sppt.attr, + &dev_attr_nv_dynamic_boost.attr, + &dev_attr_nv_temp_target.attr, + &dev_attr_mcu_powersave.attr, + &dev_attr_boot_sound.attr, + &dev_attr_panel_od.attr, + &dev_attr_mini_led_mode.attr, + &dev_attr_available_mini_led_mode.attr, + &dev_attr_throttle_thermal_policy.attr, +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ NULL }; @@ -4477,7 +4579,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, devid = ASUS_WMI_DEVID_LID_RESUME; else if (attr == &dev_attr_als_enable.attr) devid = ASUS_WMI_DEVID_ALS_ENABLE; - else if (attr == &dev_attr_charge_mode.attr) + else if (attr == &dev_attr_fan_boost_mode.attr) + ok = asus->fan_boost_mode_available; + +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) + if (attr == &dev_attr_charge_mode.attr) devid = ASUS_WMI_DEVID_CHARGE_MODE; else if (attr == &dev_attr_egpu_enable.attr) ok = asus->egpu_enable_available; @@ -4496,7 +4602,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, else if (attr == &dev_attr_ppt_pl1_spl.attr) devid = ASUS_WMI_DEVID_PPT_PL1_SPL; else if (attr == &dev_attr_ppt_fppt.attr) - devid = ASUS_WMI_DEVID_PPT_FPPT; + devid = ASUS_WMI_DEVID_PPT_PL3_FPPT; else if (attr == &dev_attr_ppt_apu_sppt.attr) devid = ASUS_WMI_DEVID_PPT_APU_SPPT; else if (attr == &dev_attr_ppt_platform_sppt.attr) @@ -4515,6 +4621,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, ok = asus->mini_led_dev_id != 0; else if (attr == &dev_attr_available_mini_led_mode.attr) ok = asus->mini_led_dev_id != 0; +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ if (devid != -1) { ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); @@ -4770,6 +4877,7 @@ static int asus_wmi_add(struct platform_device *pdev) } /* ensure defaults for tunables */ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) asus->ppt_pl2_sppt = 5; asus->ppt_pl1_spl = 5; asus->ppt_apu_sppt = 5; @@ -4792,17 +4900,18 @@ static int asus_wmi_add(struct platform_device *pdev) asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX; else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO)) asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO; - - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE)) - asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE; - else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2)) - asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2; +#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY)) asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY; else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO)) asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE)) + asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE; + else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2)) + asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2; + err = fan_boost_mode_check_present(asus); if (err) goto fail_fan_boost_mode; diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c new file mode 100644 index 000000000000..41a24e091248 --- /dev/null +++ b/drivers/platform/x86/ayaneo-ec.c @@ -0,0 +1,593 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Platform driver for the Embedded Controller (EC) of Ayaneo devices. Handles + * hwmon (fan speed, fan control), battery charge limits, and magic module + * control (connected modules, controller disconnection). + * + * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev> + */ + +#include <linux/acpi.h> +#include <linux/bits.h> +#include <linux/dmi.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/power_supply.h> +#include <linux/sysfs.h> +#include <acpi/battery.h> + +#define AYANEO_PWM_ENABLE_REG 0x4A +#define AYANEO_PWM_REG 0x4B +#define AYANEO_PWM_MODE_AUTO 0x00 +#define AYANEO_PWM_MODE_MANUAL 0x01 + +#define AYANEO_FAN_REG 0x76 + +#define EC_CHARGE_CONTROL_BEHAVIOURS \ + (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \ + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) +#define AYANEO_CHARGE_REG 0x1e +#define AYANEO_CHARGE_VAL_AUTO 0xaa +#define AYANEO_CHARGE_VAL_INHIBIT 0x55 + +#define AYANEO_POWER_REG 0x2d +#define AYANEO_POWER_OFF 0xfe +#define AYANEO_POWER_ON 0xff +#define AYANEO_MODULE_REG 0x2f +#define AYANEO_MODULE_LEFT BIT(0) +#define AYANEO_MODULE_RIGHT BIT(1) +#define AYANEO_MODULE_MASK (AYANEO_MODULE_LEFT | AYANEO_MODULE_RIGHT) + +struct ayaneo_ec_quirk { + bool has_fan_control; + bool has_charge_control; + bool has_magic_modules; +}; + +struct ayaneo_ec_platform_data { + struct platform_device *pdev; + struct ayaneo_ec_quirk *quirks; + struct acpi_battery_hook battery_hook; + + // Protects access to restore_pwm + struct mutex hwmon_lock; + bool restore_charge_limit; + bool restore_pwm; +}; + +static const struct ayaneo_ec_quirk quirk_fan = { + .has_fan_control = true, +}; + +static const struct ayaneo_ec_quirk quirk_charge_limit = { + .has_fan_control = true, + .has_charge_control = true, +}; + +static const struct ayaneo_ec_quirk quirk_ayaneo3 = { + .has_fan_control = true, + .has_charge_control = true, + .has_magic_modules = true, +}; + +static const struct dmi_system_id dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"), + }, + .driver_data = (void *)&quirk_fan, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_MATCH(DMI_BOARD_NAME, "FLIP"), + }, + .driver_data = (void *)&quirk_fan, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_MATCH(DMI_BOARD_NAME, "GEEK"), + }, + .driver_data = (void *)&quirk_fan, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), + }, + .driver_data = (void *)&quirk_charge_limit, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"), + }, + .driver_data = (void *)&quirk_charge_limit, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"), + }, + .driver_data = (void *)&quirk_charge_limit, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), + }, + .driver_data = (void *)&quirk_charge_limit, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"), + }, + .driver_data = (void *)&quirk_charge_limit, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 3"), + }, + .driver_data = (void *)&quirk_ayaneo3, + }, + {}, +}; + +/* Callbacks for hwmon interface */ +static umode_t ayaneo_ec_hwmon_is_visible(const void *drvdata, + enum hwmon_sensor_types type, u32 attr, + int channel) +{ + switch (type) { + case hwmon_fan: + return 0444; + case hwmon_pwm: + return 0644; + default: + return 0; + } +} + +static int ayaneo_ec_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + u8 tmp; + int ret; + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + ret = ec_read(AYANEO_FAN_REG, &tmp); + if (ret) + return ret; + *val = tmp << 8; + ret = ec_read(AYANEO_FAN_REG + 1, &tmp); + if (ret) + return ret; + *val |= tmp; + return 0; + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + ret = ec_read(AYANEO_PWM_REG, &tmp); + if (ret) + return ret; + if (tmp > 100) + return -EIO; + *val = (255 * tmp) / 100; + return 0; + case hwmon_pwm_enable: + ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp); + if (ret) + return ret; + if (tmp == AYANEO_PWM_MODE_MANUAL) + *val = 1; + else if (tmp == AYANEO_PWM_MODE_AUTO) + *val = 2; + else + return -EIO; + return 0; + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +static int ayaneo_ec_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct ayaneo_ec_platform_data *data = dev_get_drvdata(dev); + int ret; + + guard(mutex)(&data->hwmon_lock); + + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_enable: + data->restore_pwm = false; + switch (val) { + case 1: + return ec_write(AYANEO_PWM_ENABLE_REG, + AYANEO_PWM_MODE_MANUAL); + case 2: + return ec_write(AYANEO_PWM_ENABLE_REG, + AYANEO_PWM_MODE_AUTO); + default: + return -EINVAL; + } + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + if (data->restore_pwm) { + /* + * Defer restoring PWM control to after + * userspace resumes successfully + */ + ret = ec_write(AYANEO_PWM_ENABLE_REG, + AYANEO_PWM_MODE_MANUAL); + if (ret) + return ret; + data->restore_pwm = false; + } + return ec_write(AYANEO_PWM_REG, (val * 100) / 255); + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +static const struct hwmon_ops ayaneo_ec_hwmon_ops = { + .is_visible = ayaneo_ec_hwmon_is_visible, + .read = ayaneo_ec_read, + .write = ayaneo_ec_write, +}; + +static const struct hwmon_channel_info *const ayaneo_ec_sensors[] = { + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), + HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE), + NULL, +}; + +static const struct hwmon_chip_info ayaneo_ec_chip_info = { + .ops = &ayaneo_ec_hwmon_ops, + .info = ayaneo_ec_sensors, +}; + +static int ayaneo_psy_ext_get_prop(struct power_supply *psy, + const struct power_supply_ext *ext, + void *data, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret; + u8 tmp; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + ret = ec_read(AYANEO_CHARGE_REG, &tmp); + if (ret) + return ret; + + if (tmp == AYANEO_CHARGE_VAL_INHIBIT) + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + else + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; + return 0; + default: + return -EINVAL; + } +} + +static int ayaneo_psy_ext_set_prop(struct power_supply *psy, + const struct power_supply_ext *ext, + void *data, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + u8 raw_val; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + switch (val->intval) { + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: + raw_val = AYANEO_CHARGE_VAL_AUTO; + break; + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: + raw_val = AYANEO_CHARGE_VAL_INHIBIT; + break; + default: + return -EINVAL; + } + return ec_write(AYANEO_CHARGE_REG, raw_val); + default: + return -EINVAL; + } +} + +static int ayaneo_psy_prop_is_writeable(struct power_supply *psy, + const struct power_supply_ext *ext, + void *data, + enum power_supply_property psp) +{ + return true; +} + +static const enum power_supply_property ayaneo_psy_ext_props[] = { + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, +}; + +static const struct power_supply_ext ayaneo_psy_ext = { + .name = "ayaneo-charge-control", + .properties = ayaneo_psy_ext_props, + .num_properties = ARRAY_SIZE(ayaneo_psy_ext_props), + .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS, + .get_property = ayaneo_psy_ext_get_prop, + .set_property = ayaneo_psy_ext_set_prop, + .property_is_writeable = ayaneo_psy_prop_is_writeable, +}; + +static int ayaneo_add_battery(struct power_supply *battery, + struct acpi_battery_hook *hook) +{ + struct ayaneo_ec_platform_data *data = + container_of(hook, struct ayaneo_ec_platform_data, battery_hook); + + return power_supply_register_extension(battery, &ayaneo_psy_ext, + &data->pdev->dev, NULL); +} + +static int ayaneo_remove_battery(struct power_supply *battery, + struct acpi_battery_hook *hook) +{ + power_supply_unregister_extension(battery, &ayaneo_psy_ext); + return 0; +} + +static ssize_t controller_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + bool value; + int ret; + + ret = kstrtobool(buf, &value); + if (ret) + return ret; + + ret = ec_write(AYANEO_POWER_REG, value ? AYANEO_POWER_ON : AYANEO_POWER_OFF); + if (ret) + return ret; + + return count; +} + +static ssize_t controller_power_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u8 val; + + ret = ec_read(AYANEO_POWER_REG, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", val == AYANEO_POWER_ON); +} + +static DEVICE_ATTR_RW(controller_power); + +static ssize_t controller_modules_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 unconnected_modules; + char *out; + int ret; + + ret = ec_read(AYANEO_MODULE_REG, &unconnected_modules); + if (ret) + return ret; + + switch (~unconnected_modules & AYANEO_MODULE_MASK) { + case AYANEO_MODULE_LEFT | AYANEO_MODULE_RIGHT: + out = "both"; + break; + case AYANEO_MODULE_LEFT: + out = "left"; + break; + case AYANEO_MODULE_RIGHT: + out = "right"; + break; + default: + out = "none"; + break; + } + + return sysfs_emit(buf, "%s\n", out); +} + +static DEVICE_ATTR_RO(controller_modules); + +static struct attribute *aya_mm_attrs[] = { + &dev_attr_controller_power.attr, + &dev_attr_controller_modules.attr, + NULL +}; + +static umode_t aya_mm_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct platform_device *pdev = to_platform_device(dev); + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev); + + if (data->quirks->has_magic_modules) + return attr->mode; + return 0; +} + +static const struct attribute_group aya_mm_attribute_group = { + .is_visible = aya_mm_is_visible, + .attrs = aya_mm_attrs, +}; + +static const struct attribute_group *ayaneo_ec_groups[] = { + &aya_mm_attribute_group, + NULL +}; + +static int ayaneo_ec_probe(struct platform_device *pdev) +{ + const struct dmi_system_id *dmi_entry; + struct ayaneo_ec_platform_data *data; + struct device *hwdev; + int ret; + + dmi_entry = dmi_first_match(dmi_table); + if (!dmi_entry) + return -ENODEV; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->pdev = pdev; + data->quirks = dmi_entry->driver_data; + ret = devm_mutex_init(&pdev->dev, &data->hwmon_lock); + if (ret) + return ret; + platform_set_drvdata(pdev, data); + + if (data->quirks->has_fan_control) { + hwdev = devm_hwmon_device_register_with_info(&pdev->dev, + "ayaneo_ec", data, &ayaneo_ec_chip_info, NULL); + if (IS_ERR(hwdev)) + return PTR_ERR(hwdev); + } + + if (data->quirks->has_charge_control) { + data->battery_hook.add_battery = ayaneo_add_battery; + data->battery_hook.remove_battery = ayaneo_remove_battery; + data->battery_hook.name = "Ayaneo Battery"; + ret = devm_battery_hook_register(&pdev->dev, &data->battery_hook); + if (ret) + return ret; + } + + return 0; +} + +static int ayaneo_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev); + int ret; + u8 tmp; + + if (data->quirks->has_charge_control) { + ret = ec_read(AYANEO_CHARGE_REG, &tmp); + if (ret) + return ret; + + data->restore_charge_limit = tmp == AYANEO_CHARGE_VAL_INHIBIT; + } + + if (data->quirks->has_fan_control) { + ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp); + if (ret) + return ret; + + data->restore_pwm = tmp == AYANEO_PWM_MODE_MANUAL; + + /* + * Release the fan when entering hibernation to avoid + * overheating if hibernation fails and hangs. + */ + if (data->restore_pwm) { + ret = ec_write(AYANEO_PWM_ENABLE_REG, AYANEO_PWM_MODE_AUTO); + if (ret) + return ret; + } + } + + return 0; +} + +static int ayaneo_restore(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev); + int ret; + + if (data->quirks->has_charge_control && data->restore_charge_limit) { + ret = ec_write(AYANEO_CHARGE_REG, AYANEO_CHARGE_VAL_INHIBIT); + if (ret) + return ret; + } + + return 0; +} + +static const struct dev_pm_ops ayaneo_pm_ops = { + .freeze = ayaneo_freeze, + .restore = ayaneo_restore, +}; + +static struct platform_driver ayaneo_platform_driver = { + .driver = { + .name = "ayaneo-ec", + .dev_groups = ayaneo_ec_groups, + .pm = pm_sleep_ptr(&ayaneo_pm_ops), + }, + .probe = ayaneo_ec_probe, +}; + +static struct platform_device *ayaneo_platform_device; + +static int __init ayaneo_ec_init(void) +{ + ayaneo_platform_device = + platform_create_bundle(&ayaneo_platform_driver, + ayaneo_ec_probe, NULL, 0, NULL, 0); + + return PTR_ERR_OR_ZERO(ayaneo_platform_device); +} + +static void __exit ayaneo_ec_exit(void) +{ + platform_device_unregister(ayaneo_platform_device); + platform_driver_unregister(&ayaneo_platform_driver); +} + +MODULE_DEVICE_TABLE(dmi, dmi_table); + +module_init(ayaneo_ec_init); +module_exit(ayaneo_ec_exit); + +MODULE_AUTHOR("Antheas Kapenekakis <lkml@antheas.dev>"); +MODULE_DESCRIPTION("Ayaneo Embedded Controller (EC) platform features"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index fadf7aac6779..1418bd326edf 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -235,11 +235,6 @@ enum AWCC_THERMAL_TABLES { AWCC_THERMAL_TABLE_USTT = 0xA, }; -enum AWCC_SPECIAL_THERMAL_CODES { - AWCC_SPECIAL_PROFILE_CUSTOM = 0x00, - AWCC_SPECIAL_PROFILE_GMODE = 0xAB, -}; - enum AWCC_TEMP_SENSOR_TYPES { AWCC_TEMP_SENSOR_CPU = 0x01, AWCC_TEMP_SENSOR_FRONT = 0x03, @@ -266,17 +261,18 @@ enum AWCC_FAN_TYPES { }; enum awcc_thermal_profile { - AWCC_PROFILE_USTT_BALANCED, - AWCC_PROFILE_USTT_BALANCED_PERFORMANCE, - AWCC_PROFILE_USTT_COOL, - AWCC_PROFILE_USTT_QUIET, - AWCC_PROFILE_USTT_PERFORMANCE, - AWCC_PROFILE_USTT_LOW_POWER, - AWCC_PROFILE_LEGACY_QUIET, - AWCC_PROFILE_LEGACY_BALANCED, - AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE, - AWCC_PROFILE_LEGACY_PERFORMANCE, - AWCC_PROFILE_LAST, + AWCC_PROFILE_SPECIAL_CUSTOM = 0x00, + AWCC_PROFILE_LEGACY_QUIET = 0x96, + AWCC_PROFILE_LEGACY_BALANCED = 0x97, + AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE = 0x98, + AWCC_PROFILE_LEGACY_PERFORMANCE = 0x99, + AWCC_PROFILE_USTT_BALANCED = 0xA0, + AWCC_PROFILE_USTT_BALANCED_PERFORMANCE = 0xA1, + AWCC_PROFILE_USTT_COOL = 0xA2, + AWCC_PROFILE_USTT_QUIET = 0xA3, + AWCC_PROFILE_USTT_PERFORMANCE = 0xA4, + AWCC_PROFILE_USTT_LOW_POWER = 0xA5, + AWCC_PROFILE_SPECIAL_GMODE = 0xAB, }; struct wmax_led_args { @@ -332,19 +328,6 @@ struct awcc_priv { u32 gpio_count; }; -static const enum platform_profile_option awcc_mode_to_platform_profile[AWCC_PROFILE_LAST] = { - [AWCC_PROFILE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED, - [AWCC_PROFILE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, - [AWCC_PROFILE_USTT_COOL] = PLATFORM_PROFILE_COOL, - [AWCC_PROFILE_USTT_QUIET] = PLATFORM_PROFILE_QUIET, - [AWCC_PROFILE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, - [AWCC_PROFILE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER, - [AWCC_PROFILE_LEGACY_QUIET] = PLATFORM_PROFILE_QUIET, - [AWCC_PROFILE_LEGACY_BALANCED] = PLATFORM_PROFILE_BALANCED, - [AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, - [AWCC_PROFILE_LEGACY_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, -}; - static struct awcc_quirks *awcc; /* @@ -562,21 +545,41 @@ const struct attribute_group wmax_deepsleep_attribute_group = { /* * AWCC Helpers */ -static bool is_awcc_thermal_profile_id(u8 code) +static int awcc_profile_to_pprof(enum awcc_thermal_profile profile, + enum platform_profile_option *pprof) { - u8 table = FIELD_GET(AWCC_THERMAL_TABLE_MASK, code); - u8 mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, code); - - if (mode >= AWCC_PROFILE_LAST) - return false; - - if (table == AWCC_THERMAL_TABLE_LEGACY && mode >= AWCC_PROFILE_LEGACY_QUIET) - return true; - - if (table == AWCC_THERMAL_TABLE_USTT && mode <= AWCC_PROFILE_USTT_LOW_POWER) - return true; + switch (profile) { + case AWCC_PROFILE_SPECIAL_CUSTOM: + *pprof = PLATFORM_PROFILE_CUSTOM; + break; + case AWCC_PROFILE_LEGACY_QUIET: + case AWCC_PROFILE_USTT_QUIET: + *pprof = PLATFORM_PROFILE_QUIET; + break; + case AWCC_PROFILE_LEGACY_BALANCED: + case AWCC_PROFILE_USTT_BALANCED: + *pprof = PLATFORM_PROFILE_BALANCED; + break; + case AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE: + case AWCC_PROFILE_USTT_BALANCED_PERFORMANCE: + *pprof = PLATFORM_PROFILE_BALANCED_PERFORMANCE; + break; + case AWCC_PROFILE_LEGACY_PERFORMANCE: + case AWCC_PROFILE_USTT_PERFORMANCE: + case AWCC_PROFILE_SPECIAL_GMODE: + *pprof = PLATFORM_PROFILE_PERFORMANCE; + break; + case AWCC_PROFILE_USTT_COOL: + *pprof = PLATFORM_PROFILE_COOL; + break; + case AWCC_PROFILE_USTT_LOW_POWER: + *pprof = PLATFORM_PROFILE_LOW_POWER; + break; + default: + return -EINVAL; + } - return false; + return 0; } static int awcc_wmi_command(struct wmi_device *wdev, u32 method_id, @@ -1225,24 +1228,7 @@ static int awcc_platform_profile_get(struct device *dev, if (ret) return ret; - switch (out_data) { - case AWCC_SPECIAL_PROFILE_CUSTOM: - *profile = PLATFORM_PROFILE_CUSTOM; - return 0; - case AWCC_SPECIAL_PROFILE_GMODE: - *profile = PLATFORM_PROFILE_PERFORMANCE; - return 0; - default: - break; - } - - if (!is_awcc_thermal_profile_id(out_data)) - return -ENODATA; - - out_data = FIELD_GET(AWCC_THERMAL_MODE_MASK, out_data); - *profile = awcc_mode_to_platform_profile[out_data]; - - return 0; + return awcc_profile_to_pprof(out_data, profile); } static int awcc_platform_profile_set(struct device *dev, @@ -1279,7 +1265,6 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices) { enum platform_profile_option profile; struct awcc_priv *priv = drvdata; - enum awcc_thermal_profile mode; u8 id, offset = 0; int ret; @@ -1301,15 +1286,20 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices) if (ret) return ret; - if (!is_awcc_thermal_profile_id(id)) { + /* + * G-Mode profile ID is not listed consistently across modeles + * that support it, therefore we handle it through quirks. + */ + if (id == AWCC_PROFILE_SPECIAL_GMODE) + continue; + + ret = awcc_profile_to_pprof(id, &profile); + if (ret) { dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id); continue; } - mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, id); - profile = awcc_mode_to_platform_profile[mode]; priv->supported_profiles[profile] = id; - __set_bit(profile, choices); } @@ -1318,14 +1308,14 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices) if (awcc->gmode) { priv->supported_profiles[PLATFORM_PROFILE_PERFORMANCE] = - AWCC_SPECIAL_PROFILE_GMODE; + AWCC_PROFILE_SPECIAL_GMODE; __set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); } /* Every model supports the "custom" profile */ priv->supported_profiles[PLATFORM_PROFILE_CUSTOM] = - AWCC_SPECIAL_PROFILE_CUSTOM; + AWCC_PROFILE_SPECIAL_CUSTOM; __set_bit(PLATFORM_PROFILE_CUSTOM, choices); diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c index 7a20f68ae206..c9236738f896 100644 --- a/drivers/platform/x86/gpd-pocket-fan.c +++ b/drivers/platform/x86/gpd-pocket-fan.c @@ -112,14 +112,14 @@ set_speed: gpd_pocket_fan_set_speed(fan, speed); /* When mostly idle (low temp/speed), slow down the poll interval. */ - queue_delayed_work(system_wq, &fan->work, + queue_delayed_work(system_percpu_wq, &fan->work, msecs_to_jiffies(4000 / (speed + 1))); } static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan) { fan->last_speed = -1; - mod_delayed_work(system_wq, &fan->work, 0); + mod_delayed_work(system_percpu_wq, &fan->work, 0); } static int gpd_pocket_fan_probe(struct platform_device *pdev) diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index ad9d9f97960f..f4ea1ea05997 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -63,12 +63,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4"); * contains "PerformanceControl". */ static const char * const omen_thermal_profile_boards[] = { - "84DA", "84DB", "84DC", "8574", "8575", "860A", "87B5", "8572", "8573", - "8600", "8601", "8602", "8605", "8606", "8607", "8746", "8747", "8749", - "874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C", - "88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD", - "88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912", - "8917", "8918", "8949", "894A", "89EB", "8BAD", "8A42", "8A15" + "84DA", "84DB", "84DC", + "8572", "8573", "8574", "8575", + "8600", "8601", "8602", "8603", "8604", "8605", "8606", "8607", "860A", + "8746", "8747", "8748", "8749", "874A", "8786", "8787", "8788", "878A", + "878B", "878C", "87B5", + "886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6", + "88F7", "88FD", "88FE", "88FF", + "8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB", + "8A15", "8A42", + "8BAD", }; /* DMI Board names of Omen laptops that are specifically set to be thermal @@ -76,7 +80,8 @@ static const char * const omen_thermal_profile_boards[] = { * the get system design information WMI call returns */ static const char * const omen_thermal_profile_force_v0_boards[] = { - "8607", "8746", "8747", "8749", "874A", "8748" + "8607", + "8746", "8747", "8748", "8749", "874A", }; /* DMI board names of Omen laptops that have a thermal profile timer which will @@ -84,12 +89,13 @@ static const char * const omen_thermal_profile_force_v0_boards[] = { * "balanced" when reaching zero. */ static const char * const omen_timed_thermal_profile_boards[] = { - "8BAD", "8A42", "8A15" + "8A15", "8A42", + "8BAD", }; /* DMI Board names of Victus 16-d1xxx laptops */ static const char * const victus_thermal_profile_boards[] = { - "8A25" + "8A25", }; /* DMI Board names of Victus 16-r and Victus 16-s laptops */ diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c index 9c07a7faf18f..560cc063198e 100644 --- a/drivers/platform/x86/intel/hid.c +++ b/drivers/platform/x86/intel/hid.c @@ -177,6 +177,18 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite Dragonfly G2 Notebook PC"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 10 Tablet RA00260"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 12 Tablet RA02260"), + }, + }, { } }; diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c index 17ad87b392ab..eb23bc68340a 100644 --- a/drivers/platform/x86/intel/pmc/arl.c +++ b/drivers/platform/x86/intel/pmc/arl.c @@ -281,6 +281,7 @@ static const struct pmc_reg_map arl_socs_reg_map = { .etr3_offset = ETR3_OFFSET, .pson_residency_offset = TGL_PSON_RESIDENCY_OFFSET, .pson_residency_counter_step = TGL_PSON_RES_COUNTER_STEP, + .lpm_req_guid = SOCS_LPM_REQ_GUID, }; static const struct pmc_bit_map arl_pchs_ltr_show_map[] = { @@ -648,26 +649,23 @@ static const struct pmc_reg_map arl_pchs_reg_map = { .lpm_num_maps = ADL_LPM_NUM_MAPS, .lpm_reg_index = ARL_LPM_REG_INDEX, .etr3_offset = ETR3_OFFSET, + .lpm_req_guid = PCHS_LPM_REQ_GUID, }; static struct pmc_info arl_pmc_info_list[] = { { - .guid = IOEP_LPM_REQ_GUID, .devid = PMC_DEVID_ARL_IOEP, .map = &mtl_ioep_reg_map, }, { - .guid = SOCS_LPM_REQ_GUID, .devid = PMC_DEVID_ARL_SOCS, .map = &arl_socs_reg_map, }, { - .guid = PCHS_LPM_REQ_GUID, .devid = PMC_DEVID_ARL_PCHS, .map = &arl_pchs_reg_map, }, { - .guid = SOCM_LPM_REQ_GUID, .devid = PMC_DEVID_ARL_SOCM, .map = &mtl_socm_reg_map, }, @@ -720,9 +718,10 @@ static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_ return generic_core_init(pmcdev, pmc_dev_info); } +static u32 ARL_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, 0x0}; struct pmc_dev_info arl_pmc_dev = { .pci_func = 0, - .dmu_guid = ARL_PMT_DMU_GUID, + .dmu_guids = ARL_PMT_DMU_GUIDS, .regmap_list = arl_pmc_info_list, .map = &arl_socs_reg_map, .sub_req_show = &pmc_core_substate_req_regs_fops, @@ -732,9 +731,10 @@ struct pmc_dev_info arl_pmc_dev = { .sub_req = pmc_core_pmt_get_lpm_req, }; +static u32 ARL_H_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, ARL_H_PMT_DMU_GUID, 0x0}; struct pmc_dev_info arl_h_pmc_dev = { .pci_func = 2, - .dmu_guid = ARL_PMT_DMU_GUID, + .dmu_guids = ARL_H_PMT_DMU_GUIDS, .regmap_list = arl_pmc_info_list, .map = &mtl_socm_reg_map, .sub_req_show = &pmc_core_substate_req_regs_fops, diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index ac3d19ae8c56..7d7ae8a40b0e 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -20,6 +20,7 @@ enum header_type { #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dmi.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/module.h> #include <linux/pci.h> @@ -311,20 +312,20 @@ static inline u8 pmc_core_reg_read_byte(struct pmc *pmc, int offset) } static void pmc_core_display_map(struct seq_file *s, int index, int idx, int ip, - int pmc_index, u8 pf_reg, const struct pmc_bit_map **pf_map) + int pmc_idx, u8 pf_reg, const struct pmc_bit_map **pf_map) { seq_printf(s, "PMC%d:PCH IP: %-2d - %-32s\tState: %s\n", - pmc_index, ip, pf_map[idx][index].name, + pmc_idx, ip, pf_map[idx][index].name, pf_map[idx][index].bit_mask & pf_reg ? "Off" : "On"); } static int pmc_core_ppfear_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - unsigned int i; + unsigned int pmc_idx; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { - struct pmc *pmc = pmcdev->pmcs[i]; + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { + struct pmc *pmc = pmcdev->pmcs[pmc_idx]; const struct pmc_bit_map **maps; u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES]; unsigned int index, iter, idx, ip = 0; @@ -342,7 +343,7 @@ static int pmc_core_ppfear_show(struct seq_file *s, void *unused) for (idx = 0; maps[idx]; idx++) { for (index = 0; maps[idx][index].name && index < pmc->map->ppfear_buckets * 8; ip++, index++) - pmc_core_display_map(s, index, idx, ip, i, + pmc_core_display_map(s, index, idx, ip, pmc_idx, pf_regs[index / 8], maps); } } @@ -471,7 +472,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore) struct pmc *pmc; const struct pmc_reg_map *map; u32 reg; - unsigned int pmc_index; + unsigned int pmc_idx; int ltr_index; ltr_index = value; @@ -479,8 +480,8 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore) * is based on the contiguous indexes from ltr_show output. * pmc index and ltr index needs to be calculated from it. */ - for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs) && ltr_index >= 0; pmc_index++) { - pmc = pmcdev->pmcs[pmc_index]; + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs) && ltr_index >= 0; pmc_idx++) { + pmc = pmcdev->pmcs[pmc_idx]; if (!pmc) continue; @@ -497,10 +498,10 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore) ltr_index = ltr_index - (map->ltr_ignore_max + 2) - 1; } - if (pmc_index >= ARRAY_SIZE(pmcdev->pmcs) || ltr_index < 0) + if (pmc_idx >= ARRAY_SIZE(pmcdev->pmcs) || ltr_index < 0) return -EINVAL; - pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_index, ltr_index); + pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_idx, ltr_index); guard(mutex)(&pmcdev->lock); @@ -635,14 +636,14 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused) u64 decoded_snoop_ltr, decoded_non_snoop_ltr, val; u32 ltr_raw_data, scale; u16 snoop_ltr, nonsnoop_ltr; - unsigned int i, index, ltr_index = 0; + unsigned int pmc_idx, index, ltr_index = 0; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { struct pmc *pmc; const struct pmc_bit_map *map; u32 ltr_ign_reg; - pmc = pmcdev->pmcs[i]; + pmc = pmcdev->pmcs[pmc_idx]; if (!pmc) continue; @@ -676,7 +677,7 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused) } seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\tLTR_IGNORE: %d\n", - ltr_index, i, map[index].name, ltr_raw_data, + ltr_index, pmc_idx, map[index].name, ltr_raw_data, decoded_non_snoop_ltr, decoded_snoop_ltr, ltr_ign_data); ltr_index++; @@ -689,15 +690,15 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr); static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - unsigned int pmcidx; + unsigned int pmc_idx; - for (pmcidx = 0; pmcidx < ARRAY_SIZE(pmcdev->pmcs); pmcidx++) { + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) { const struct pmc_bit_map **maps; unsigned int arr_size, r_idx; u32 offset, counter; struct pmc *pmc; - pmc = pmcdev->pmcs[pmcidx]; + pmc = pmcdev->pmcs[pmc_idx]; if (!pmc) continue; maps = pmc->map->s0ix_blocker_maps; @@ -711,7 +712,7 @@ static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused) if (!map->blk) continue; counter = pmc_core_reg_read(pmc, offset); - seq_printf(s, "PMC%d:%-30s %-30d\n", pmcidx, + seq_printf(s, "PMC%d:%-30s %-30d\n", pmc_idx, map->name, counter); offset += map->blk * S0IX_BLK_SIZE; } @@ -723,13 +724,13 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker); static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev) { - unsigned int i; + unsigned int pmc_idx; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) { + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) { struct pmc *pmc; u32 ltr_ign; - pmc = pmcdev->pmcs[i]; + pmc = pmcdev->pmcs[pmc_idx]; if (!pmc) continue; @@ -750,12 +751,12 @@ static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev) static void pmc_core_ltr_restore_all(struct pmc_dev *pmcdev) { - unsigned int i; + unsigned int pmc_idx; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) { + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) { struct pmc *pmc; - pmc = pmcdev->pmcs[i]; + pmc = pmcdev->pmcs[pmc_idx]; if (!pmc) continue; @@ -794,10 +795,10 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res); static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - unsigned int i; + unsigned int pmc_idx; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { - struct pmc *pmc = pmcdev->pmcs[i]; + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { + struct pmc *pmc = pmcdev->pmcs[pmc_idx]; const struct pmc_bit_map **maps; u32 offset; @@ -805,7 +806,7 @@ static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused) continue; maps = pmc->map->lpm_sts; offset = pmc->map->lpm_status_offset; - pmc_core_lpm_display(pmc, NULL, s, offset, i, "STATUS", maps); + pmc_core_lpm_display(pmc, NULL, s, offset, pmc_idx, "STATUS", maps); } return 0; @@ -815,10 +816,10 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_sts_regs); static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - unsigned int i; + unsigned int pmc_idx; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { - struct pmc *pmc = pmcdev->pmcs[i]; + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { + struct pmc *pmc = pmcdev->pmcs[pmc_idx]; const struct pmc_bit_map **maps; u32 offset; @@ -826,7 +827,7 @@ static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused) continue; maps = pmc->map->lpm_sts; offset = pmc->map->lpm_live_status_offset; - pmc_core_lpm_display(pmc, NULL, s, offset, i, "LIVE_STATUS", maps); + pmc_core_lpm_display(pmc, NULL, s, offset, pmc_idx, "LIVE_STATUS", maps); } return 0; @@ -919,11 +920,11 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused) u32 sts_offset; u32 sts_offset_live; u32 *lpm_req_regs; - unsigned int mp, pmc_index; + unsigned int mp, pmc_idx; int num_maps; - for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs); ++pmc_index) { - struct pmc *pmc = pmcdev->pmcs[pmc_index]; + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { + struct pmc *pmc = pmcdev->pmcs[pmc_idx]; const struct pmc_bit_map **maps; if (!pmc) @@ -944,7 +945,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused) continue; /* Display the header */ - pmc_core_substate_req_header_show(s, pmc_index, HEADER_STATUS); + pmc_core_substate_req_header_show(s, pmc_idx, HEADER_STATUS); /* Loop over maps */ for (mp = 0; mp < num_maps; mp++) { @@ -982,7 +983,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused) } /* Display the element name in the first column */ - seq_printf(s, "pmc%d: %34s |", pmc_index, map[i].name); + seq_printf(s, "pmc%d: %34s |", pmc_idx, map[i].name); /* Loop over the enabled states and display if required */ pmc_for_each_mode(mode, pmcdev) { @@ -1281,7 +1282,20 @@ int get_primary_reg_base(struct pmc *pmc) return 0; } -void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid) +static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev, u32 *guids) +{ + struct telem_endpoint *ep; + unsigned int i; + + for (i = 0; guids[i]; i++) { + ep = pmt_telem_find_and_register_endpoint(pcidev, guids[i], 0); + if (!IS_ERR(ep)) + return ep; + } + return ERR_PTR(-ENODEV); +} + +void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids) { struct telem_endpoint *ep; struct pci_dev *pcidev; @@ -1292,7 +1306,7 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid) return; } - ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0); + ep = pmc_core_register_endpoint(pcidev, guids); pci_dev_put(pcidev); if (IS_ERR(ep)) { dev_err(&pmcdev->pdev->dev, @@ -1302,8 +1316,6 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid) } pmcdev->punit_ep = ep; - - pmcdev->has_die_c6 = true; pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET; } @@ -1423,22 +1435,13 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info pmcdev->dbgfs_dir, primary_pmc, &pmc_core_pson_residency); } - if (pmcdev->has_die_c6) { + if (pmcdev->punit_ep) { debugfs_create_file("die_c6_us_show", 0444, pmcdev->dbgfs_dir, pmcdev, &pmc_core_die_c6_us_fops); } } -static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map) -{ - for (; list->map; ++list) - if (list->map == map) - return list->guid; - - return 0; -} - /* * This function retrieves low power mode requirement data from PMC Low * Power Mode (LPM) table. @@ -1553,26 +1556,24 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info * { struct pci_dev *pcidev __free(pci_dev_put) = NULL; struct telem_endpoint *ep; - unsigned int i; - u32 guid; + unsigned int pmc_idx; int ret; pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, pmc_dev_info->pci_func)); if (!pcidev) return -ENODEV; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { struct pmc *pmc; - pmc = pmcdev->pmcs[i]; + pmc = pmcdev->pmcs[pmc_idx]; if (!pmc) continue; - guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map); - if (!guid) + if (!pmc->map->lpm_req_guid) return -ENXIO; - ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0); + ep = pmt_telem_find_and_register_endpoint(pcidev, pmc->map->lpm_req_guid, 0); if (IS_ERR(ep)) { dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep); return -EPROBE_DEFER; @@ -1596,7 +1597,7 @@ static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 return NULL; } -static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index) +static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_idx) { struct pmc_ssram_telemetry pmc_ssram_telemetry; @@ -1604,7 +1605,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index) struct pmc *pmc; int ret; - ret = pmc_ssram_telemetry_get_pmc_info(pmc_index, &pmc_ssram_telemetry); + ret = pmc_ssram_telemetry_get_pmc_info(pmc_idx, &pmc_ssram_telemetry); if (ret) return ret; @@ -1612,7 +1613,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index) if (!map) return -ENODEV; - pmc = pmcdev->pmcs[pmc_index]; + pmc = pmcdev->pmcs[pmc_idx]; /* Memory for primary PMC has been allocated */ if (!pmc) { pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL); @@ -1629,7 +1630,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index) return -ENOMEM; } - pmcdev->pmcs[pmc_index] = pmc; + pmcdev->pmcs[pmc_idx] = pmc; return 0; } @@ -1689,8 +1690,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) } pmc_core_get_low_power_modes(pmcdev); - if (pmc_dev_info->dmu_guid) - pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guid); + if (pmc_dev_info->dmu_guids) + pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guids); if (ssram) { ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info); @@ -1701,8 +1702,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) return 0; unmap_regbase: - for (unsigned int i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { - struct pmc *pmc = pmcdev->pmcs[i]; + for (unsigned int pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { + struct pmc *pmc = pmcdev->pmcs[pmc_idx]; if (pmc && pmc->regbase) iounmap(pmc->regbase); @@ -1795,10 +1796,10 @@ static void pmc_core_do_dmi_quirks(struct pmc *pmc) static void pmc_core_clean_structure(struct platform_device *pdev) { struct pmc_dev *pmcdev = platform_get_drvdata(pdev); - unsigned int i; + unsigned int pmc_idx; - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { - struct pmc *pmc = pmcdev->pmcs[i]; + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { + struct pmc *pmc = pmcdev->pmcs[pmc_idx]; if (pmc && pmc->regbase) iounmap(pmc->regbase); @@ -1958,7 +1959,7 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev) struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; const struct pmc_bit_map **maps = pmc->map->lpm_sts; int offset = pmc->map->lpm_status_offset; - unsigned int i; + unsigned int pmc_idx, i; /* Check if the syspend used S0ix */ if (pm_suspend_via_firmware()) @@ -1996,13 +1997,13 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev) if (pmc->map->slps0_dbg_maps) pmc_core_slps0_display(pmc, dev, NULL); - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { - struct pmc *pmc = pmcdev->pmcs[i]; + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) { + struct pmc *pmc = pmcdev->pmcs[pmc_idx]; if (!pmc) continue; if (pmc->map->lpm_sts) - pmc_core_lpm_display(pmc, dev, NULL, offset, i, "STATUS", maps); + pmc_core_lpm_display(pmc, dev, NULL, offset, pmc_idx, "STATUS", maps); } return 0; diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h index f4dadb696a31..272fb4f57f34 100644 --- a/drivers/platform/x86/intel/pmc/core.h +++ b/drivers/platform/x86/intel/pmc/core.h @@ -282,7 +282,8 @@ enum ppfear_regs { /* Die C6 from PUNIT telemetry */ #define MTL_PMT_DMU_DIE_C6_OFFSET 15 #define MTL_PMT_DMU_GUID 0x1A067102 -#define ARL_PMT_DMU_GUID 0x1A06A000 +#define ARL_PMT_DMU_GUID 0x1A06A102 +#define ARL_H_PMT_DMU_GUID 0x1A06A101 #define LNL_PMC_MMIO_REG_LEN 0x2708 #define LNL_PMC_LTR_OSSE 0x1B88 @@ -303,6 +304,8 @@ enum ppfear_regs { /* Wildcat Lake */ #define WCL_PMC_LTR_RESERVED 0x1B64 #define WCL_PCD_PMC_MMIO_REG_LEN 0x3178 +#define WCL_NUM_S0IX_BLOCKER 94 +#define WCL_BLK_REQ_OFFSET 50 /* SSRAM PMC Device ID */ /* LNL */ @@ -355,6 +358,7 @@ struct pmc_bit_map { * @s0ix_blocker_offset PWRMBASE offset to S0ix blocker counter * @num_s0ix_blocker: Number of S0ix blockers * @blocker_req_offset: Telemetry offset to S0ix blocker low power mode substate requirement table + * @lpm_req_guid: Telemetry GUID to read low power mode substate requirement table * * Each PCH has unique set of register offsets and bit indexes. This structure * captures them to have a common implementation. @@ -396,6 +400,8 @@ struct pmc_reg_map { const u8 *lpm_reg_index; const u32 pson_residency_offset; const u32 pson_residency_counter_step; + /* GUID for telemetry regions */ + const u32 lpm_req_guid; }; /** @@ -405,7 +411,6 @@ struct pmc_reg_map { * specific attributes */ struct pmc_info { - u32 guid; u16 devid; const struct pmc_reg_map *map; }; @@ -465,7 +470,6 @@ struct pmc_dev { u64 *pkgc_res_cnt; u8 num_of_pkgc; - bool has_die_c6; u32 die_c6_offset; struct telem_endpoint *punit_ep; struct pmc_info *regmap_list; @@ -481,7 +485,7 @@ enum pmc_index { /** * struct pmc_dev_info - Structure to keep PMC device info * @pci_func: Function number of the primary PMC - * @dmu_guid: Die Management Unit GUID + * @dmu_guids: List of Die Management Unit GUID * @regmap_list: Pointer to a list of pmc_info structure that could be * available for the platform. When set, this field implies * SSRAM support. @@ -495,7 +499,7 @@ enum pmc_index { */ struct pmc_dev_info { u8 pci_func; - u32 dmu_guid; + u32 *dmu_guids; struct pmc_info *regmap_list; const struct pmc_reg_map *map; const struct file_operations *sub_req_show; @@ -532,7 +536,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore); int pmc_core_resume_common(struct pmc_dev *pmcdev); int get_primary_reg_base(struct pmc *pmc); void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev); -void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid); +void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids); void pmc_core_set_device_d3(unsigned int device); int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info); diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c index 6fa027e7071f..1cd81ee54dcf 100644 --- a/drivers/platform/x86/intel/pmc/lnl.c +++ b/drivers/platform/x86/intel/pmc/lnl.c @@ -533,11 +533,11 @@ static const struct pmc_reg_map lnl_socm_reg_map = { .s0ix_blocker_maps = lnl_blk_maps, .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET, .lpm_reg_index = LNL_LPM_REG_INDEX, + .lpm_req_guid = SOCM_LPM_REQ_GUID, }; static struct pmc_info lnl_pmc_info_list[] = { { - .guid = SOCM_LPM_REQ_GUID, .devid = PMC_DEVID_LNL_SOCM, .map = &lnl_socm_reg_map, }, diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c index 0b87e10f864e..57508cbf9cd4 100644 --- a/drivers/platform/x86/intel/pmc/mtl.c +++ b/drivers/platform/x86/intel/pmc/mtl.c @@ -473,6 +473,7 @@ const struct pmc_reg_map mtl_socm_reg_map = { .lpm_status_offset = MTL_LPM_STATUS_OFFSET, .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET, .lpm_reg_index = MTL_LPM_REG_INDEX, + .lpm_req_guid = SOCP_LPM_REQ_GUID, }; static const struct pmc_bit_map mtl_ioep_pfear_map[] = { @@ -797,6 +798,7 @@ const struct pmc_reg_map mtl_ioep_reg_map = { .lpm_en_offset = MTL_LPM_EN_OFFSET, .lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET, .lpm_reg_index = MTL_LPM_REG_INDEX, + .lpm_req_guid = IOEP_LPM_REQ_GUID, }; static const struct pmc_bit_map mtl_ioem_pfear_map[] = { @@ -944,21 +946,19 @@ static const struct pmc_reg_map mtl_ioem_reg_map = { .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2, .lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET, .lpm_reg_index = MTL_LPM_REG_INDEX, + .lpm_req_guid = IOEM_LPM_REQ_GUID, }; static struct pmc_info mtl_pmc_info_list[] = { { - .guid = SOCP_LPM_REQ_GUID, .devid = PMC_DEVID_MTL_SOCM, .map = &mtl_socm_reg_map, }, { - .guid = IOEP_LPM_REQ_GUID, .devid = PMC_DEVID_MTL_IOEP, .map = &mtl_ioep_reg_map, }, { - .guid = IOEM_LPM_REQ_GUID, .devid = PMC_DEVID_MTL_IOEM, .map = &mtl_ioem_reg_map }, @@ -992,9 +992,10 @@ static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in return generic_core_init(pmcdev, pmc_dev_info); } +static u32 MTL_PMT_DMU_GUIDS[] = {MTL_PMT_DMU_GUID, 0x0}; struct pmc_dev_info mtl_pmc_dev = { .pci_func = 2, - .dmu_guid = MTL_PMT_DMU_GUID, + .dmu_guids = MTL_PMT_DMU_GUIDS, .regmap_list = mtl_pmc_info_list, .map = &mtl_socm_reg_map, .sub_req_show = &pmc_core_substate_req_regs_fops, diff --git a/drivers/platform/x86/intel/pmc/ptl.c b/drivers/platform/x86/intel/pmc/ptl.c index 1b35b84e06fa..1f48e2bbc699 100644 --- a/drivers/platform/x86/intel/pmc/ptl.c +++ b/drivers/platform/x86/intel/pmc/ptl.c @@ -528,16 +528,15 @@ static const struct pmc_reg_map ptl_pcdp_reg_map = { .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET, .num_s0ix_blocker = PTL_NUM_S0IX_BLOCKER, .blocker_req_offset = PTL_BLK_REQ_OFFSET, + .lpm_req_guid = PCDP_LPM_REQ_GUID, }; static struct pmc_info ptl_pmc_info_list[] = { { - .guid = PCDP_LPM_REQ_GUID, .devid = PMC_DEVID_PTL_PCDH, .map = &ptl_pcdp_reg_map, }, { - .guid = PCDP_LPM_REQ_GUID, .devid = PMC_DEVID_PTL_PCDP, .map = &ptl_pcdp_reg_map, }, diff --git a/drivers/platform/x86/intel/pmc/wcl.c b/drivers/platform/x86/intel/pmc/wcl.c index 85e90a639e65..a45707e6364f 100644 --- a/drivers/platform/x86/intel/pmc/wcl.c +++ b/drivers/platform/x86/intel/pmc/wcl.c @@ -11,6 +11,9 @@ #include "core.h" +/* PMC SSRAM PMT Telemetry GUIDS */ +#define PCDN_LPM_REQ_GUID 0x33747648 + static const struct pmc_bit_map wcl_pcdn_pfear_map[] = { {"PMC_0", BIT(0)}, {"FUSE_OSSE", BIT(1)}, @@ -453,6 +456,17 @@ static const struct pmc_reg_map wcl_pcdn_reg_map = { .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET, .s0ix_blocker_maps = wcl_pcdn_blk_maps, .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET, + .num_s0ix_blocker = WCL_NUM_S0IX_BLOCKER, + .blocker_req_offset = WCL_BLK_REQ_OFFSET, + .lpm_req_guid = PCDN_LPM_REQ_GUID, +}; + +static struct pmc_info wcl_pmc_info_list[] = { + { + .devid = PMC_DEVID_WCL_PCDN, + .map = &wcl_pcdn_reg_map, + }, + {} }; #define WCL_NPU_PCI_DEV 0xfd3e @@ -479,8 +493,12 @@ static int wcl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in } struct pmc_dev_info wcl_pmc_dev = { + .pci_func = 2, + .regmap_list = wcl_pmc_info_list, .map = &wcl_pcdn_reg_map, + .sub_req_show = &pmc_core_substate_blk_req_fops, .suspend = cnl_suspend, .resume = wcl_resume, .init = wcl_core_init, + .sub_req = pmc_core_pmt_get_blk_sub_req, }; diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index f66f0ce8559b..ecfc7703f201 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -765,6 +765,7 @@ static const struct intel_vsec_platform_info lnl_info = { #define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d #define PCI_DEVICE_ID_INTEL_VSEC_LNL_M 0x647d #define PCI_DEVICE_ID_INTEL_VSEC_PTL 0xb07d +#define PCI_DEVICE_ID_INTEL_VSEC_WCL 0xfd7d static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, @@ -776,6 +777,7 @@ static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_LNL_M, &lnl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_PTL, &mtl_info) }, + { PCI_DEVICE_DATA(INTEL, VSEC_WCL, &mtl_info) }, { } }; MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c index fcebfbaf0460..5171a077f62c 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -31,6 +31,7 @@ #include <linux/power_supply.h> #include <linux/rfkill.h> #include <linux/seq_file.h> +#include <linux/string_choices.h> #include <linux/sysfs.h> #include <linux/types.h> #include <linux/wmi.h> @@ -62,13 +63,27 @@ enum { CFG_OSD_CAM_BIT = 31, }; +/* + * There are two charge modes supported by the GBMD/SBMC interface: + * - "Rapid Charge": increase power to speed up charging + * - "Conservation Mode": stop charging at 60-80% (depends on model) + * + * The interface doesn't prohibit enabling both modes at the same time. + * However, doing so is essentially meaningless, and the manufacturer utilities + * on Windows always make them mutually exclusive. + */ + enum { + GBMD_RAPID_CHARGE_STATE_BIT = 2, GBMD_CONSERVATION_STATE_BIT = 5, + GBMD_RAPID_CHARGE_SUPPORTED_BIT = 17, }; enum { SBMC_CONSERVATION_ON = 3, SBMC_CONSERVATION_OFF = 5, + SBMC_RAPID_CHARGE_ON = 7, + SBMC_RAPID_CHARGE_OFF = 8, }; enum { @@ -158,6 +173,7 @@ struct ideapad_rfk_priv { struct ideapad_private { struct acpi_device *adev; struct mutex vpc_mutex; /* protects the VPC calls */ + struct mutex gbmd_sbmc_mutex; /* protects GBMD/SBMC calls */ struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM]; struct platform_device *platform_device; @@ -166,9 +182,11 @@ struct ideapad_private { struct ideapad_dytc_priv *dytc; struct dentry *debug; struct acpi_battery_hook battery_hook; + const struct power_supply_ext *battery_ext; unsigned long cfg; unsigned long r_touchpad_val; struct { + bool rapid_charge : 1; bool conservation_mode : 1; bool dytc : 1; bool fan_mode : 1; @@ -455,37 +473,40 @@ static int debugfs_status_show(struct seq_file *s, void *data) struct ideapad_private *priv = s->private; unsigned long value; - guard(mutex)(&priv->vpc_mutex); - - if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value)) - seq_printf(s, "Backlight max: %lu\n", value); - if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value)) - seq_printf(s, "Backlight now: %lu\n", value); - if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value)) - seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value); - - seq_puts(s, "=====================\n"); - - if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value)) - seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value); - if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value)) - seq_printf(s, "Wifi status: %s (%lu)\n", value ? "on" : "off", value); - if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value)) - seq_printf(s, "BT status: %s (%lu)\n", value ? "on" : "off", value); - if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value)) - seq_printf(s, "3G status: %s (%lu)\n", value ? "on" : "off", value); + scoped_guard(mutex, &priv->vpc_mutex) { + if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value)) + seq_printf(s, "Backlight max: %lu\n", value); + if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value)) + seq_printf(s, "Backlight now: %lu\n", value); + if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value)) + seq_printf(s, "BL power value: %s (%lu)\n", str_on_off(value), value); + + seq_puts(s, "=====================\n"); + + if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value)) + seq_printf(s, "Radio status: %s (%lu)\n", str_on_off(value), value); + if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value)) + seq_printf(s, "Wifi status: %s (%lu)\n", str_on_off(value), value); + if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value)) + seq_printf(s, "BT status: %s (%lu)\n", str_on_off(value), value); + if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value)) + seq_printf(s, "3G status: %s (%lu)\n", str_on_off(value), value); + + seq_puts(s, "=====================\n"); + + if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) + seq_printf(s, "Touchpad status: %s (%lu)\n", str_on_off(value), value); + if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value)) + seq_printf(s, "Camera status: %s (%lu)\n", str_on_off(value), value); + } seq_puts(s, "=====================\n"); - if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) - seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value); - if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value)) - seq_printf(s, "Camera status: %s (%lu)\n", value ? "on" : "off", value); - - seq_puts(s, "=====================\n"); + scoped_guard(mutex, &priv->gbmd_sbmc_mutex) { + if (!eval_gbmd(priv->adev->handle, &value)) + seq_printf(s, "GBMD: %#010lx\n", value); + } - if (!eval_gbmd(priv->adev->handle, &value)) - seq_printf(s, "GBMD: %#010lx\n", value); if (!eval_hals(priv->adev->handle, &value)) seq_printf(s, "HALS: %#010lx\n", value); @@ -622,10 +643,16 @@ static ssize_t conservation_mode_show(struct device *dev, show_conservation_mode_deprecation_warning(dev); - err = eval_gbmd(priv->adev->handle, &result); - if (err) - return err; + scoped_guard(mutex, &priv->gbmd_sbmc_mutex) { + err = eval_gbmd(priv->adev->handle, &result); + if (err) + return err; + } + /* + * For backward compatibility, ignore Rapid Charge while reporting the + * state of Conservation Mode. + */ return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result)); } @@ -643,6 +670,18 @@ static ssize_t conservation_mode_store(struct device *dev, if (err) return err; + guard(mutex)(&priv->gbmd_sbmc_mutex); + + /* + * Prevent mutually exclusive modes from being set at the same time, + * but do not disable Rapid Charge while disabling Conservation Mode. + */ + if (priv->features.rapid_charge && state) { + err = exec_sbmc(priv->adev->handle, SBMC_RAPID_CHARGE_OFF); + if (err) + return err; + } + err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF); if (err) return err; @@ -2007,15 +2046,39 @@ static int ideapad_psy_ext_set_prop(struct power_supply *psy, const union power_supply_propval *val) { struct ideapad_private *priv = ext_data; + unsigned long op1, op2; + int err; switch (val->intval) { + case POWER_SUPPLY_CHARGE_TYPE_FAST: + if (WARN_ON(!priv->features.rapid_charge)) + return -EINVAL; + + op1 = SBMC_CONSERVATION_OFF; + op2 = SBMC_RAPID_CHARGE_ON; + break; case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE: - return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_ON); + op1 = SBMC_RAPID_CHARGE_OFF; + op2 = SBMC_CONSERVATION_ON; + break; case POWER_SUPPLY_CHARGE_TYPE_STANDARD: - return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_OFF); + op1 = SBMC_RAPID_CHARGE_OFF; + op2 = SBMC_CONSERVATION_OFF; + break; default: return -EINVAL; } + + guard(mutex)(&priv->gbmd_sbmc_mutex); + + /* If !rapid_charge, op1 must be SBMC_RAPID_CHARGE_OFF. Skip it. */ + if (priv->features.rapid_charge) { + err = exec_sbmc(priv->adev->handle, op1); + if (err) + return err; + } + + return exec_sbmc(priv->adev->handle, op2); } static int ideapad_psy_ext_get_prop(struct power_supply *psy, @@ -2025,14 +2088,29 @@ static int ideapad_psy_ext_get_prop(struct power_supply *psy, union power_supply_propval *val) { struct ideapad_private *priv = ext_data; + bool is_rapid_charge, is_conservation; unsigned long result; int err; - err = eval_gbmd(priv->adev->handle, &result); - if (err) - return err; + scoped_guard(mutex, &priv->gbmd_sbmc_mutex) { + err = eval_gbmd(priv->adev->handle, &result); + if (err) + return err; + } + + is_rapid_charge = (priv->features.rapid_charge && + test_bit(GBMD_RAPID_CHARGE_STATE_BIT, &result)); + is_conservation = test_bit(GBMD_CONSERVATION_STATE_BIT, &result); + + if (unlikely(is_rapid_charge && is_conservation)) { + dev_err(&priv->platform_device->dev, + "unexpected charge_types: both [Fast] and [Long_Life] are enabled\n"); + return -EINVAL; + } - if (test_bit(GBMD_CONSERVATION_STATE_BIT, &result)) + if (is_rapid_charge) + val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; + else if (is_conservation) val->intval = POWER_SUPPLY_CHARGE_TYPE_LONGLIFE; else val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; @@ -2052,29 +2130,42 @@ static const enum power_supply_property ideapad_power_supply_props[] = { POWER_SUPPLY_PROP_CHARGE_TYPES, }; -static const struct power_supply_ext ideapad_battery_ext = { - .name = "ideapad_laptop", - .properties = ideapad_power_supply_props, - .num_properties = ARRAY_SIZE(ideapad_power_supply_props), - .charge_types = (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) | - BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)), - .get_property = ideapad_psy_ext_get_prop, - .set_property = ideapad_psy_ext_set_prop, - .property_is_writeable = ideapad_psy_prop_is_writeable, -}; +#define DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(_name, _charge_types) \ + static const struct power_supply_ext _name = { \ + .name = "ideapad_laptop", \ + .properties = ideapad_power_supply_props, \ + .num_properties = ARRAY_SIZE(ideapad_power_supply_props), \ + .charge_types = _charge_types, \ + .get_property = ideapad_psy_ext_get_prop, \ + .set_property = ideapad_psy_ext_set_prop, \ + .property_is_writeable = ideapad_psy_prop_is_writeable, \ + } + +DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v1, + (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) | + BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)) +); + +DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v2, + (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) | + BIT(POWER_SUPPLY_CHARGE_TYPE_FAST) | + BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)) +); static int ideapad_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook); - return power_supply_register_extension(battery, &ideapad_battery_ext, + return power_supply_register_extension(battery, priv->battery_ext, &priv->platform_device->dev, priv); } static int ideapad_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { - power_supply_unregister_extension(battery, &ideapad_battery_ext); + struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook); + + power_supply_unregister_extension(battery, priv->battery_ext); return 0; } @@ -2099,14 +2190,25 @@ static int ideapad_check_features(struct ideapad_private *priv) priv->features.fan_mode = true; if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) { - priv->features.conservation_mode = true; - priv->battery_hook.add_battery = ideapad_battery_add; - priv->battery_hook.remove_battery = ideapad_battery_remove; - priv->battery_hook.name = "Ideapad Battery Extension"; - - err = devm_battery_hook_register(&priv->platform_device->dev, &priv->battery_hook); - if (err) - return err; + /* Not acquiring gbmd_sbmc_mutex as race condition is impossible on init */ + if (!eval_gbmd(handle, &val)) { + priv->features.conservation_mode = true; + priv->features.rapid_charge = test_bit(GBMD_RAPID_CHARGE_SUPPORTED_BIT, + &val); + + priv->battery_ext = priv->features.rapid_charge + ? &ideapad_battery_ext_v2 + : &ideapad_battery_ext_v1; + + priv->battery_hook.add_battery = ideapad_battery_add; + priv->battery_hook.remove_battery = ideapad_battery_remove; + priv->battery_hook.name = "Ideapad Battery Extension"; + + err = devm_battery_hook_register(&priv->platform_device->dev, + &priv->battery_hook); + if (err) + return err; + } } if (acpi_has_method(handle, "DYTC")) @@ -2292,6 +2394,10 @@ static int ideapad_acpi_add(struct platform_device *pdev) if (err) return err; + err = devm_mutex_init(&pdev->dev, &priv->gbmd_sbmc_mutex); + if (err) + return err; + err = ideapad_check_features(priv); if (err) return err; diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c index 0eb7fe8222f4..381836d29a96 100644 --- a/drivers/platform/x86/lenovo/wmi-gamezone.c +++ b/drivers/platform/x86/lenovo/wmi-gamezone.c @@ -171,14 +171,10 @@ static int lwmi_gz_profile_get(struct device *dev, *profile = PLATFORM_PROFILE_BALANCED; break; case LWMI_GZ_THERMAL_MODE_PERFORMANCE: - if (priv->extreme_supported) { - *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE; - break; - } *profile = PLATFORM_PROFILE_PERFORMANCE; break; case LWMI_GZ_THERMAL_MODE_EXTREME: - *profile = PLATFORM_PROFILE_PERFORMANCE; + *profile = PLATFORM_PROFILE_MAX_POWER; break; case LWMI_GZ_THERMAL_MODE_CUSTOM: *profile = PLATFORM_PROFILE_CUSTOM; @@ -218,16 +214,12 @@ static int lwmi_gz_profile_set(struct device *dev, case PLATFORM_PROFILE_BALANCED: mode = LWMI_GZ_THERMAL_MODE_BALANCED; break; - case PLATFORM_PROFILE_BALANCED_PERFORMANCE: - mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE; - break; case PLATFORM_PROFILE_PERFORMANCE: - if (priv->extreme_supported) { - mode = LWMI_GZ_THERMAL_MODE_EXTREME; - break; - } mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE; break; + case PLATFORM_PROFILE_MAX_POWER: + mode = LWMI_GZ_THERMAL_MODE_EXTREME; + break; case PLATFORM_PROFILE_CUSTOM: mode = LWMI_GZ_THERMAL_MODE_CUSTOM; break; @@ -274,8 +266,23 @@ static const struct dmi_system_id fwbug_list[] = { }, .driver_data = &quirk_no_extreme_bug, }, + { + .ident = "Legion Go 8ASP2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8ASP2"), + }, + .driver_data = &quirk_no_extreme_bug, + }, + { + .ident = "Legion Go 8AHP2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8AHP2"), + }, + .driver_data = &quirk_no_extreme_bug, + }, {}, - }; /** @@ -338,7 +345,7 @@ static int lwmi_gz_platform_profile_probe(void *drvdata, unsigned long *choices) priv->extreme_supported = lwmi_gz_extreme_supported(profile_support_ver); if (priv->extreme_supported) - set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices); + set_bit(PLATFORM_PROFILE_MAX_POWER, choices); return 0; } diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index 6af6cf477c5b..f92e89c75db9 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -19,6 +19,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/string_choices.h> #include <linux/types.h> #include <acpi/battery.h> @@ -42,6 +43,7 @@ MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages"); #define LG_ADDRESS_SPACE_ID 0x8F #define LG_ADDRESS_SPACE_DEBUG_FLAG_ADR 0x00 +#define LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR 0x01 #define LG_ADDRESS_SPACE_FAN_MODE_ADR 0x03 #define LG_ADDRESS_SPACE_DTTM_FLAG_ADR 0x20 @@ -668,6 +670,15 @@ static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physic byte = value & 0xFF; switch (address) { + case LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR: + /* + * The HD audio power field is not affected by the DTTM flag, + * so we have to manually check fw_debug. + */ + if (fw_debug) + dev_dbg(dev, "HD audio power %s\n", str_enabled_disabled(byte)); + + return AE_OK; case LG_ADDRESS_SPACE_FAN_MODE_ADR: /* * The fan mode field is not affected by the DTTM flag, so we diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c index 54377b282ff8..144a454103b9 100644 --- a/drivers/platform/x86/oxpec.c +++ b/drivers/platform/x86/oxpec.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Platform driver for OneXPlayer and AOKZOE devices. For the time being, - * it also exposes fan controls for AYANEO, and OrangePi Handhelds via - * hwmon sysfs. + * Platform driver for OneXPlayer and AOKZOE devices. * * Fan control is provided via pwm interface in the range [0-255]. * Old AMD boards use [0-100] as range in the EC, the written value is @@ -43,14 +41,6 @@ static bool unlock_global_acpi_lock(void) enum oxp_board { aok_zoe_a1 = 1, - aya_neo_2, - aya_neo_air, - aya_neo_air_1s, - aya_neo_air_plus_mendo, - aya_neo_air_pro, - aya_neo_flip, - aya_neo_geek, - aya_neo_kun, orange_pi_neo, oxp_2, oxp_fly, @@ -133,62 +123,6 @@ static const struct dmi_system_id dmi_table[] = { }, { .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"), - }, - .driver_data = (void *)aya_neo_2, - }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), - }, - .driver_data = (void *)aya_neo_air, - }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"), - }, - .driver_data = (void *)aya_neo_air_1s, - }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"), - }, - .driver_data = (void *)aya_neo_air_plus_mendo, - }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), - }, - .driver_data = (void *)aya_neo_air_pro, - }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_MATCH(DMI_BOARD_NAME, "FLIP"), - }, - .driver_data = (void *)aya_neo_flip, - }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_MATCH(DMI_BOARD_NAME, "GEEK"), - }, - .driver_data = (void *)aya_neo_geek, - }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"), - }, - .driver_data = (void *)aya_neo_kun, - }, - { - .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"), }, @@ -672,13 +606,6 @@ static int oxp_pwm_enable(void) case orange_pi_neo: return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); case aok_zoe_a1: - case aya_neo_2: - case aya_neo_air: - case aya_neo_air_plus_mendo: - case aya_neo_air_pro: - case aya_neo_flip: - case aya_neo_geek: - case aya_neo_kun: case oxp_2: case oxp_fly: case oxp_mini_amd: @@ -699,14 +626,6 @@ static int oxp_pwm_disable(void) case orange_pi_neo: return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); case aok_zoe_a1: - case aya_neo_2: - case aya_neo_air: - case aya_neo_air_1s: - case aya_neo_air_plus_mendo: - case aya_neo_air_pro: - case aya_neo_flip: - case aya_neo_geek: - case aya_neo_kun: case oxp_2: case oxp_fly: case oxp_mini_amd: @@ -727,14 +646,6 @@ static int oxp_pwm_read(long *val) case orange_pi_neo: return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val); case aok_zoe_a1: - case aya_neo_2: - case aya_neo_air: - case aya_neo_air_1s: - case aya_neo_air_plus_mendo: - case aya_neo_air_pro: - case aya_neo_flip: - case aya_neo_geek: - case aya_neo_kun: case oxp_2: case oxp_fly: case oxp_mini_amd: @@ -774,14 +685,6 @@ static int oxp_pwm_fan_speed(long *val) case oxp_g1_i: return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val); case aok_zoe_a1: - case aya_neo_2: - case aya_neo_air: - case aya_neo_air_1s: - case aya_neo_air_plus_mendo: - case aya_neo_air_pro: - case aya_neo_flip: - case aya_neo_geek: - case aya_neo_kun: case oxp_fly: case oxp_mini_amd: case oxp_mini_amd_a07: @@ -810,14 +713,6 @@ static int oxp_pwm_input_write(long val) /* scale to range [0-184] */ val = (val * 184) / 255; return write_to_ec(OXP_SENSOR_PWM_REG, val); - case aya_neo_2: - case aya_neo_air: - case aya_neo_air_1s: - case aya_neo_air_plus_mendo: - case aya_neo_air_pro: - case aya_neo_flip: - case aya_neo_geek: - case aya_neo_kun: case oxp_mini_amd: case oxp_mini_amd_a07: /* scale to range [0-100] */ @@ -854,14 +749,6 @@ static int oxp_pwm_input_read(long *val) /* scale from range [0-184] */ *val = (*val * 255) / 184; break; - case aya_neo_2: - case aya_neo_air: - case aya_neo_air_1s: - case aya_neo_air_plus_mendo: - case aya_neo_air_pro: - case aya_neo_flip: - case aya_neo_geek: - case aya_neo_kun: case oxp_mini_amd: case oxp_mini_amd_a07: ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index db030b0f176a..1a369334f9cb 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -22,6 +22,7 @@ #define IRQ_RESOURCE_GPIO 1 #define IRQ_RESOURCE_APIC 2 #define IRQ_RESOURCE_AUTO 3 +#define IRQ_RESOURCE_OPT BIT(2) enum smi_bus_type { SMI_I2C, @@ -64,6 +65,10 @@ static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev, dev_dbg(&pdev->dev, "Using platform irq\n"); break; } + if (inst->flags & IRQ_RESOURCE_OPT) { + dev_dbg(&pdev->dev, "No irq\n"); + return 0; + } break; case IRQ_RESOURCE_GPIO: ret = acpi_dev_gpio_irq_get(adev, inst->irq_idx); @@ -386,10 +391,10 @@ static const struct smi_node cs35l57_hda = { static const struct smi_node tas2781_hda = { .instances = { - { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 }, - { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 }, - { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 }, - { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 }, + { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 }, + { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 }, + { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 }, + { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 }, {} }, .bus_type = SMI_AUTO_DETECT, diff --git a/drivers/platform/x86/uniwill/Kconfig b/drivers/platform/x86/uniwill/Kconfig new file mode 100644 index 000000000000..d07cc8440188 --- /dev/null +++ b/drivers/platform/x86/uniwill/Kconfig @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Uniwill X86 Platform Specific Drivers +# + +menuconfig X86_PLATFORM_DRIVERS_UNIWILL + bool "Uniwill X86 Platform Specific Device Drivers" + depends on X86_PLATFORM_DEVICES + help + Say Y here to see options for device drivers for various + Uniwill x86 platforms, including many OEM laptops originally + manufactured by Uniwill. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if X86_PLATFORM_DRIVERS_UNIWILL + +config UNIWILL_LAPTOP + tristate "Uniwill Laptop Extras" + default m + depends on ACPI + depends on ACPI_WMI + depends on ACPI_BATTERY + depends on HWMON + depends on INPUT + depends on LEDS_CLASS_MULTICOLOR + depends on DMI + select REGMAP + select INPUT_SPARSEKMAP + help + This driver adds support for various extra features found on Uniwill laptops, + like the lightbar, hwmon sensors and hotkeys. It also supports many OEM laptops + originally manufactured by Uniwill. + + If you have such a laptop, say Y or M here. + +endif diff --git a/drivers/platform/x86/uniwill/Makefile b/drivers/platform/x86/uniwill/Makefile new file mode 100644 index 000000000000..05cd1747a240 --- /dev/null +++ b/drivers/platform/x86/uniwill/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for linux/drivers/platform/x86/uniwill +# Uniwill X86 Platform Specific Drivers +# + +obj-$(CONFIG_UNIWILL_LAPTOP) += uniwill-laptop.o +uniwill-laptop-y := uniwill-acpi.o uniwill-wmi.o diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c new file mode 100644 index 000000000000..bd7e63dd5181 --- /dev/null +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c @@ -0,0 +1,1912 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Linux driver for Uniwill notebooks. + * + * Special thanks go to PÅ‘cze Barnabás, Christoffer Sandberg and Werner Sembach + * for supporting the development of this driver either through prior work or + * by answering questions regarding the underlying ACPI and WMI interfaces. + * + * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/acpi.h> +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/device/driver.h> +#include <linux/dmi.h> +#include <linux/errno.h> +#include <linux/fixp-arith.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/input/sparse-keymap.h> +#include <linux/kernel.h> +#include <linux/kstrtox.h> +#include <linux/leds.h> +#include <linux/led-class-multicolor.h> +#include <linux/limits.h> +#include <linux/list.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/notifier.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/printk.h> +#include <linux/regmap.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <acpi/battery.h> + +#include "uniwill-wmi.h" + +#define EC_ADDR_BAT_POWER_UNIT_1 0x0400 + +#define EC_ADDR_BAT_POWER_UNIT_2 0x0401 + +#define EC_ADDR_BAT_DESIGN_CAPACITY_1 0x0402 + +#define EC_ADDR_BAT_DESIGN_CAPACITY_2 0x0403 + +#define EC_ADDR_BAT_FULL_CAPACITY_1 0x0404 + +#define EC_ADDR_BAT_FULL_CAPACITY_2 0x0405 + +#define EC_ADDR_BAT_DESIGN_VOLTAGE_1 0x0408 + +#define EC_ADDR_BAT_DESIGN_VOLTAGE_2 0x0409 + +#define EC_ADDR_BAT_STATUS_1 0x0432 +#define BAT_DISCHARGING BIT(0) + +#define EC_ADDR_BAT_STATUS_2 0x0433 + +#define EC_ADDR_BAT_CURRENT_1 0x0434 + +#define EC_ADDR_BAT_CURRENT_2 0x0435 + +#define EC_ADDR_BAT_REMAIN_CAPACITY_1 0x0436 + +#define EC_ADDR_BAT_REMAIN_CAPACITY_2 0x0437 + +#define EC_ADDR_BAT_VOLTAGE_1 0x0438 + +#define EC_ADDR_BAT_VOLTAGE_2 0x0439 + +#define EC_ADDR_CPU_TEMP 0x043E + +#define EC_ADDR_GPU_TEMP 0x044F + +#define EC_ADDR_MAIN_FAN_RPM_1 0x0464 + +#define EC_ADDR_MAIN_FAN_RPM_2 0x0465 + +#define EC_ADDR_SECOND_FAN_RPM_1 0x046C + +#define EC_ADDR_SECOND_FAN_RPM_2 0x046D + +#define EC_ADDR_DEVICE_STATUS 0x047B +#define WIFI_STATUS_ON BIT(7) +/* BIT(5) is also unset depending on the rfkill state (bluetooth?) */ + +#define EC_ADDR_BAT_ALERT 0x0494 + +#define EC_ADDR_BAT_CYCLE_COUNT_1 0x04A6 + +#define EC_ADDR_BAT_CYCLE_COUNT_2 0x04A7 + +#define EC_ADDR_PROJECT_ID 0x0740 + +#define EC_ADDR_AP_OEM 0x0741 +#define ENABLE_MANUAL_CTRL BIT(0) +#define ITE_KBD_EFFECT_REACTIVE BIT(3) +#define FAN_ABNORMAL BIT(5) + +#define EC_ADDR_SUPPORT_5 0x0742 +#define FAN_TURBO_SUPPORTED BIT(4) +#define FAN_SUPPORT BIT(5) + +#define EC_ADDR_CTGP_DB_CTRL 0x0743 +#define CTGP_DB_GENERAL_ENABLE BIT(0) +#define CTGP_DB_DB_ENABLE BIT(1) +#define CTGP_DB_CTGP_ENABLE BIT(2) + +#define EC_ADDR_CTGP_OFFSET 0x0744 + +#define EC_ADDR_TPP_OFFSET 0x0745 + +#define EC_ADDR_MAX_TGP 0x0746 + +#define EC_ADDR_LIGHTBAR_AC_CTRL 0x0748 +#define LIGHTBAR_APP_EXISTS BIT(0) +#define LIGHTBAR_POWER_SAVE BIT(1) +#define LIGHTBAR_S0_OFF BIT(2) +#define LIGHTBAR_S3_OFF BIT(3) // Breathing animation when suspended +#define LIGHTBAR_WELCOME BIT(7) // Rainbow animation + +#define EC_ADDR_LIGHTBAR_AC_RED 0x0749 + +#define EC_ADDR_LIGHTBAR_AC_GREEN 0x074A + +#define EC_ADDR_LIGHTBAR_AC_BLUE 0x074B + +#define EC_ADDR_BIOS_OEM 0x074E +#define FN_LOCK_STATUS BIT(4) + +#define EC_ADDR_MANUAL_FAN_CTRL 0x0751 +#define FAN_LEVEL_MASK GENMASK(2, 0) +#define FAN_MODE_TURBO BIT(4) +#define FAN_MODE_HIGH BIT(5) +#define FAN_MODE_BOOST BIT(6) +#define FAN_MODE_USER BIT(7) + +#define EC_ADDR_PWM_1 0x075B + +#define EC_ADDR_PWM_2 0x075C + +/* Unreliable */ +#define EC_ADDR_SUPPORT_1 0x0765 +#define AIRPLANE_MODE BIT(0) +#define GPS_SWITCH BIT(1) +#define OVERCLOCK BIT(2) +#define MACRO_KEY BIT(3) +#define SHORTCUT_KEY BIT(4) +#define SUPER_KEY_LOCK BIT(5) +#define LIGHTBAR BIT(6) +#define FAN_BOOST BIT(7) + +#define EC_ADDR_SUPPORT_2 0x0766 +#define SILENT_MODE BIT(0) +#define USB_CHARGING BIT(1) +#define RGB_KEYBOARD BIT(2) +#define CHINA_MODE BIT(5) +#define MY_BATTERY BIT(6) + +#define EC_ADDR_TRIGGER 0x0767 +#define TRIGGER_SUPER_KEY_LOCK BIT(0) +#define TRIGGER_LIGHTBAR BIT(1) +#define TRIGGER_FAN_BOOST BIT(2) +#define TRIGGER_SILENT_MODE BIT(3) +#define TRIGGER_USB_CHARGING BIT(4) +#define RGB_APPLY_COLOR BIT(5) +#define RGB_LOGO_EFFECT BIT(6) +#define RGB_RAINBOW_EFFECT BIT(7) + +#define EC_ADDR_SWITCH_STATUS 0x0768 +#define SUPER_KEY_LOCK_STATUS BIT(0) +#define LIGHTBAR_STATUS BIT(1) +#define FAN_BOOST_STATUS BIT(2) +#define MACRO_KEY_STATUS BIT(3) +#define MY_BAT_POWER_BAT_STATUS BIT(4) + +#define EC_ADDR_RGB_RED 0x0769 + +#define EC_ADDR_RGB_GREEN 0x076A + +#define EC_ADDR_RGB_BLUE 0x076B + +#define EC_ADDR_ROMID_START 0x0770 +#define ROMID_LENGTH 14 + +#define EC_ADDR_ROMID_EXTRA_1 0x077E + +#define EC_ADDR_ROMID_EXTRA_2 0x077F + +#define EC_ADDR_BIOS_OEM_2 0x0782 +#define FAN_V2_NEW BIT(0) +#define FAN_QKEY BIT(1) +#define FAN_TABLE_OFFICE_MODE BIT(2) +#define FAN_V3 BIT(3) +#define DEFAULT_MODE BIT(4) + +#define EC_ADDR_PL1_SETTING 0x0783 + +#define EC_ADDR_PL2_SETTING 0x0784 + +#define EC_ADDR_PL4_SETTING 0x0785 + +#define EC_ADDR_FAN_DEFAULT 0x0786 +#define FAN_CURVE_LENGTH 5 + +#define EC_ADDR_KBD_STATUS 0x078C +#define KBD_WHITE_ONLY BIT(0) // ~single color +#define KBD_SINGLE_COLOR_OFF BIT(1) +#define KBD_TURBO_LEVEL_MASK GENMASK(3, 2) +#define KBD_APPLY BIT(4) +#define KBD_BRIGHTNESS GENMASK(7, 5) + +#define EC_ADDR_FAN_CTRL 0x078E +#define FAN3P5 BIT(1) +#define CHARGING_PROFILE BIT(3) +#define UNIVERSAL_FAN_CTRL BIT(6) + +#define EC_ADDR_BIOS_OEM_3 0x07A3 +#define FAN_REDUCED_DURY_CYCLE BIT(5) +#define FAN_ALWAYS_ON BIT(6) + +#define EC_ADDR_BIOS_BYTE 0x07A4 +#define FN_LOCK_SWITCH BIT(3) + +#define EC_ADDR_OEM_3 0x07A5 +#define POWER_LED_MASK GENMASK(1, 0) +#define POWER_LED_LEFT 0x00 +#define POWER_LED_BOTH 0x01 +#define POWER_LED_NONE 0x02 +#define FAN_QUIET BIT(2) +#define OVERBOOST BIT(4) +#define HIGH_POWER BIT(7) + +#define EC_ADDR_OEM_4 0x07A6 +#define OVERBOOST_DYN_TEMP_OFF BIT(1) +#define TOUCHPAD_TOGGLE_OFF BIT(6) + +#define EC_ADDR_CHARGE_CTRL 0x07B9 +#define CHARGE_CTRL_MASK GENMASK(6, 0) +#define CHARGE_CTRL_REACHED BIT(7) + +#define EC_ADDR_UNIVERSAL_FAN_CTRL 0x07C5 +#define SPLIT_TABLES BIT(7) + +#define EC_ADDR_AP_OEM_6 0x07C6 +#define ENABLE_UNIVERSAL_FAN_CTRL BIT(2) +#define BATTERY_CHARGE_FULL_OVER_24H BIT(3) +#define BATTERY_ERM_STATUS_REACHED BIT(4) + +#define EC_ADDR_CHARGE_PRIO 0x07CC +#define CHARGING_PERFORMANCE BIT(7) + +/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */ +#define EC_ADDR_LIGHTBAR_BAT_CTRL 0x07E2 + +#define EC_ADDR_LIGHTBAR_BAT_RED 0x07E3 + +#define EC_ADDR_LIGHTBAR_BAT_GREEN 0x07E4 + +#define EC_ADDR_LIGHTBAR_BAT_BLUE 0x07E5 + +#define EC_ADDR_CPU_TEMP_END_TABLE 0x0F00 + +#define EC_ADDR_CPU_TEMP_START_TABLE 0x0F10 + +#define EC_ADDR_CPU_FAN_SPEED_TABLE 0x0F20 + +#define EC_ADDR_GPU_TEMP_END_TABLE 0x0F30 + +#define EC_ADDR_GPU_TEMP_START_TABLE 0x0F40 + +#define EC_ADDR_GPU_FAN_SPEED_TABLE 0x0F50 + +/* + * Those two registers technically allow for manual fan control, + * but are unstable on some models and are likely not meant to + * be used by applications as they are only accessible when using + * the WMI interface. + */ +#define EC_ADDR_PWM_1_WRITEABLE 0x1804 + +#define EC_ADDR_PWM_2_WRITEABLE 0x1809 + +#define DRIVER_NAME "uniwill" + +/* + * The OEM software always sleeps up to 6 ms after reading/writing EC + * registers, so we emulate this behaviour for maximum compatibility. + */ +#define UNIWILL_EC_DELAY_US 6000 + +#define PWM_MAX 200 +#define FAN_TABLE_LENGTH 16 + +#define LED_CHANNELS 3 +#define LED_MAX_BRIGHTNESS 200 + +#define UNIWILL_FEATURE_FN_LOCK_TOGGLE BIT(0) +#define UNIWILL_FEATURE_SUPER_KEY_TOGGLE BIT(1) +#define UNIWILL_FEATURE_TOUCHPAD_TOGGLE BIT(2) +#define UNIWILL_FEATURE_LIGHTBAR BIT(3) +#define UNIWILL_FEATURE_BATTERY BIT(4) +#define UNIWILL_FEATURE_HWMON BIT(5) + +struct uniwill_data { + struct device *dev; + acpi_handle handle; + struct regmap *regmap; + struct acpi_battery_hook hook; + unsigned int last_charge_ctrl; + struct mutex battery_lock; /* Protects the list of currently registered batteries */ + unsigned int last_switch_status; + struct mutex super_key_lock; /* Protects the toggling of the super key lock state */ + struct list_head batteries; + struct mutex led_lock; /* Protects writes to the lightbar registers */ + struct led_classdev_mc led_mc_cdev; + struct mc_subled led_mc_subled_info[LED_CHANNELS]; + struct mutex input_lock; /* Protects input sequence during notify */ + struct input_dev *input_device; + struct notifier_block nb; +}; + +struct uniwill_battery_entry { + struct list_head head; + struct power_supply *battery; +}; + +static bool force; +module_param_unsafe(force, bool, 0); +MODULE_PARM_DESC(force, "Force loading without checking for supported devices\n"); + +/* Feature bitmask since the associated registers are not reliable */ +static unsigned int supported_features; + +static const char * const uniwill_temp_labels[] = { + "CPU", + "GPU", +}; + +static const char * const uniwill_fan_labels[] = { + "Main", + "Secondary", +}; + +static const struct key_entry uniwill_keymap[] = { + /* Reported via keyboard controller */ + { KE_IGNORE, UNIWILL_OSD_CAPSLOCK, { KEY_CAPSLOCK }}, + { KE_IGNORE, UNIWILL_OSD_NUMLOCK, { KEY_NUMLOCK }}, + + /* Reported when the user locks/unlocks the super key */ + { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE, { KEY_UNKNOWN }}, + { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE, { KEY_UNKNOWN }}, + /* Optional, might not be reported by all devices */ + { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED, { KEY_UNKNOWN }}, + + /* Reported in manual mode when toggling the airplane mode status */ + { KE_KEY, UNIWILL_OSD_RFKILL, { KEY_RFKILL }}, + { KE_IGNORE, UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }}, + { KE_IGNORE, UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }}, + + /* Reported when user wants to cycle the platform profile */ + { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }}, + + /* Reported when the user wants to adjust the brightness of the keyboard */ + { KE_KEY, UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }}, + { KE_KEY, UNIWILL_OSD_KBDILLUMUP, { KEY_KBDILLUMUP }}, + + /* Reported when the user wants to toggle the microphone mute status */ + { KE_KEY, UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }}, + + /* Reported when the user wants to toggle the mute status */ + { KE_IGNORE, UNIWILL_OSD_MUTE, { KEY_MUTE }}, + + /* Reported when the user locks/unlocks the Fn key */ + { KE_IGNORE, UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }}, + + /* Reported when the user wants to toggle the brightness of the keyboard */ + { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }}, + { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }}, + { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }}, + { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }}, + { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }}, + { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }}, + + /* FIXME: find out the exact meaning of those events */ + { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }}, + { KE_IGNORE, UNIWILL_OSD_BAT_ERM_UPDATE, { KEY_UNKNOWN }}, + + /* Reported when the user wants to toggle the benchmark mode status */ + { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN }}, + + /* Reported when the user wants to toggle the webcam */ + { KE_IGNORE, UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }}, + + { KE_END } +}; + +static int uniwill_ec_reg_write(void *context, unsigned int reg, unsigned int val) +{ + union acpi_object params[2] = { + { + .integer = { + .type = ACPI_TYPE_INTEGER, + .value = reg, + }, + }, + { + .integer = { + .type = ACPI_TYPE_INTEGER, + .value = val, + }, + }, + }; + struct uniwill_data *data = context; + struct acpi_object_list input = { + .count = ARRAY_SIZE(params), + .pointer = params, + }; + acpi_status status; + + status = acpi_evaluate_object(data->handle, "ECRW", &input, NULL); + if (ACPI_FAILURE(status)) + return -EIO; + + usleep_range(UNIWILL_EC_DELAY_US, UNIWILL_EC_DELAY_US * 2); + + return 0; +} + +static int uniwill_ec_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + union acpi_object params[1] = { + { + .integer = { + .type = ACPI_TYPE_INTEGER, + .value = reg, + }, + }, + }; + struct uniwill_data *data = context; + struct acpi_object_list input = { + .count = ARRAY_SIZE(params), + .pointer = params, + }; + unsigned long long output; + acpi_status status; + + status = acpi_evaluate_integer(data->handle, "ECRR", &input, &output); + if (ACPI_FAILURE(status)) + return -EIO; + + if (output > U8_MAX) + return -ENXIO; + + usleep_range(UNIWILL_EC_DELAY_US, UNIWILL_EC_DELAY_US * 2); + + *val = output; + + return 0; +} + +static const struct regmap_bus uniwill_ec_bus = { + .reg_write = uniwill_ec_reg_write, + .reg_read = uniwill_ec_reg_read, + .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, +}; + +static bool uniwill_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case EC_ADDR_AP_OEM: + case EC_ADDR_LIGHTBAR_AC_CTRL: + case EC_ADDR_LIGHTBAR_AC_RED: + case EC_ADDR_LIGHTBAR_AC_GREEN: + case EC_ADDR_LIGHTBAR_AC_BLUE: + case EC_ADDR_BIOS_OEM: + case EC_ADDR_TRIGGER: + case EC_ADDR_OEM_4: + case EC_ADDR_CHARGE_CTRL: + case EC_ADDR_LIGHTBAR_BAT_CTRL: + case EC_ADDR_LIGHTBAR_BAT_RED: + case EC_ADDR_LIGHTBAR_BAT_GREEN: + case EC_ADDR_LIGHTBAR_BAT_BLUE: + return true; + default: + return false; + } +} + +static bool uniwill_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case EC_ADDR_CPU_TEMP: + case EC_ADDR_GPU_TEMP: + case EC_ADDR_MAIN_FAN_RPM_1: + case EC_ADDR_MAIN_FAN_RPM_2: + case EC_ADDR_SECOND_FAN_RPM_1: + case EC_ADDR_SECOND_FAN_RPM_2: + case EC_ADDR_BAT_ALERT: + case EC_ADDR_PROJECT_ID: + case EC_ADDR_AP_OEM: + case EC_ADDR_LIGHTBAR_AC_CTRL: + case EC_ADDR_LIGHTBAR_AC_RED: + case EC_ADDR_LIGHTBAR_AC_GREEN: + case EC_ADDR_LIGHTBAR_AC_BLUE: + case EC_ADDR_BIOS_OEM: + case EC_ADDR_PWM_1: + case EC_ADDR_PWM_2: + case EC_ADDR_TRIGGER: + case EC_ADDR_SWITCH_STATUS: + case EC_ADDR_OEM_4: + case EC_ADDR_CHARGE_CTRL: + case EC_ADDR_LIGHTBAR_BAT_CTRL: + case EC_ADDR_LIGHTBAR_BAT_RED: + case EC_ADDR_LIGHTBAR_BAT_GREEN: + case EC_ADDR_LIGHTBAR_BAT_BLUE: + return true; + default: + return false; + } +} + +static bool uniwill_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case EC_ADDR_CPU_TEMP: + case EC_ADDR_GPU_TEMP: + case EC_ADDR_MAIN_FAN_RPM_1: + case EC_ADDR_MAIN_FAN_RPM_2: + case EC_ADDR_SECOND_FAN_RPM_1: + case EC_ADDR_SECOND_FAN_RPM_2: + case EC_ADDR_BAT_ALERT: + case EC_ADDR_PWM_1: + case EC_ADDR_PWM_2: + case EC_ADDR_TRIGGER: + case EC_ADDR_SWITCH_STATUS: + case EC_ADDR_CHARGE_CTRL: + return true; + default: + return false; + } +} + +static const struct regmap_config uniwill_ec_config = { + .reg_bits = 16, + .val_bits = 8, + .writeable_reg = uniwill_writeable_reg, + .readable_reg = uniwill_readable_reg, + .volatile_reg = uniwill_volatile_reg, + .can_sleep = true, + .max_register = 0xFFF, + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + if (enable) + value = FN_LOCK_STATUS; + else + value = 0; + + ret = regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS, value); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_BIOS_OEM, &value); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", !!(value & FN_LOCK_STATUS)); +} + +static DEVICE_ATTR_RW(fn_lock_toggle_enable); + +static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + guard(mutex)(&data->super_key_lock); + + ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value); + if (ret < 0) + return ret; + + /* + * We can only toggle the super key lock, so we return early if the setting + * is already in the correct state. + */ + if (enable == !(value & SUPER_KEY_LOCK_STATUS)) + return count; + + ret = regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK, + TRIGGER_SUPER_KEY_LOCK); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", !(value & SUPER_KEY_LOCK_STATUS)); +} + +static DEVICE_ATTR_RW(super_key_toggle_enable); + +static ssize_t touchpad_toggle_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + if (enable) + value = 0; + else + value = TOUCHPAD_TOGGLE_OFF; + + ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, TOUCHPAD_TOGGLE_OFF, value); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t touchpad_toggle_enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_OEM_4, &value); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", !(value & TOUCHPAD_TOGGLE_OFF)); +} + +static DEVICE_ATTR_RW(touchpad_toggle_enable); + +static ssize_t rainbow_animation_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + if (enable) + value = LIGHTBAR_WELCOME; + else + value = 0; + + guard(mutex)(&data->led_lock); + + ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_WELCOME, value); + if (ret < 0) + return ret; + + ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_WELCOME, value); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t rainbow_animation_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", !!(value & LIGHTBAR_WELCOME)); +} + +static DEVICE_ATTR_RW(rainbow_animation); + +static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + if (enable) + value = 0; + else + value = LIGHTBAR_S3_OFF; + + /* We only access a single register here, so we do not need to use data->led_lock */ + ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S3_OFF, value); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", !(value & LIGHTBAR_S3_OFF)); +} + +static DEVICE_ATTR_RW(breathing_in_suspend); + +static struct attribute *uniwill_attrs[] = { + /* Keyboard-related */ + &dev_attr_fn_lock_toggle_enable.attr, + &dev_attr_super_key_toggle_enable.attr, + &dev_attr_touchpad_toggle_enable.attr, + /* Lightbar-related */ + &dev_attr_rainbow_animation.attr, + &dev_attr_breathing_in_suspend.attr, + NULL +}; + +static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + if (attr == &dev_attr_fn_lock_toggle_enable.attr) { + if (supported_features & UNIWILL_FEATURE_FN_LOCK_TOGGLE) + return attr->mode; + } + + if (attr == &dev_attr_super_key_toggle_enable.attr) { + if (supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE) + return attr->mode; + } + + if (attr == &dev_attr_touchpad_toggle_enable.attr) { + if (supported_features & UNIWILL_FEATURE_TOUCHPAD_TOGGLE) + return attr->mode; + } + + if (attr == &dev_attr_rainbow_animation.attr || + attr == &dev_attr_breathing_in_suspend.attr) { + if (supported_features & UNIWILL_FEATURE_LIGHTBAR) + return attr->mode; + } + + return 0; +} + +static const struct attribute_group uniwill_group = { + .is_visible = uniwill_attr_is_visible, + .attrs = uniwill_attrs, +}; + +static const struct attribute_group *uniwill_groups[] = { + &uniwill_group, + NULL +}; + +static int uniwill_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long *val) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + __be16 rpm; + int ret; + + switch (type) { + case hwmon_temp: + switch (channel) { + case 0: + ret = regmap_read(data->regmap, EC_ADDR_CPU_TEMP, &value); + break; + case 1: + ret = regmap_read(data->regmap, EC_ADDR_GPU_TEMP, &value); + break; + default: + return -EOPNOTSUPP; + } + + if (ret < 0) + return ret; + + *val = value * MILLIDEGREE_PER_DEGREE; + return 0; + case hwmon_fan: + switch (channel) { + case 0: + ret = regmap_bulk_read(data->regmap, EC_ADDR_MAIN_FAN_RPM_1, &rpm, + sizeof(rpm)); + break; + case 1: + ret = regmap_bulk_read(data->regmap, EC_ADDR_SECOND_FAN_RPM_1, &rpm, + sizeof(rpm)); + break; + default: + return -EOPNOTSUPP; + } + + if (ret < 0) + return ret; + + *val = be16_to_cpu(rpm); + return 0; + case hwmon_pwm: + switch (channel) { + case 0: + ret = regmap_read(data->regmap, EC_ADDR_PWM_1, &value); + break; + case 1: + ret = regmap_read(data->regmap, EC_ADDR_PWM_2, &value); + break; + default: + return -EOPNOTSUPP; + } + + if (ret < 0) + return ret; + + *val = fixp_linear_interpolate(0, 0, PWM_MAX, U8_MAX, value); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int uniwill_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, const char **str) +{ + switch (type) { + case hwmon_temp: + *str = uniwill_temp_labels[channel]; + return 0; + case hwmon_fan: + *str = uniwill_fan_labels[channel]; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_ops uniwill_ops = { + .visible = 0444, + .read = uniwill_read, + .read_string = uniwill_read_string, +}; + +static const struct hwmon_channel_info * const uniwill_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT), + NULL +}; + +static const struct hwmon_chip_info uniwill_chip_info = { + .ops = &uniwill_ops, + .info = uniwill_info, +}; + +static int uniwill_hwmon_init(struct uniwill_data *data) +{ + struct device *hdev; + + if (!(supported_features & UNIWILL_FEATURE_HWMON)) + return 0; + + hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data, + &uniwill_chip_info, NULL); + + return PTR_ERR_OR_ZERO(hdev); +} + +static const unsigned int uniwill_led_channel_to_bat_reg[LED_CHANNELS] = { + EC_ADDR_LIGHTBAR_BAT_RED, + EC_ADDR_LIGHTBAR_BAT_GREEN, + EC_ADDR_LIGHTBAR_BAT_BLUE, +}; + +static const unsigned int uniwill_led_channel_to_ac_reg[LED_CHANNELS] = { + EC_ADDR_LIGHTBAR_AC_RED, + EC_ADDR_LIGHTBAR_AC_GREEN, + EC_ADDR_LIGHTBAR_AC_BLUE, +}; + +static int uniwill_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) +{ + struct led_classdev_mc *led_mc_cdev = lcdev_to_mccdev(led_cdev); + struct uniwill_data *data = container_of(led_mc_cdev, struct uniwill_data, led_mc_cdev); + unsigned int value; + int ret; + + ret = led_mc_calc_color_components(led_mc_cdev, brightness); + if (ret < 0) + return ret; + + guard(mutex)(&data->led_lock); + + for (int i = 0; i < LED_CHANNELS; i++) { + /* Prevent the brightness values from overflowing */ + value = min(LED_MAX_BRIGHTNESS, data->led_mc_subled_info[i].brightness); + ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value); + if (ret < 0) + return ret; + + ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value); + if (ret < 0) + return ret; + } + + if (brightness) + value = 0; + else + value = LIGHTBAR_S0_OFF; + + ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S0_OFF, value); + if (ret < 0) + return ret; + + return regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_S0_OFF, value); +} + +#define LIGHTBAR_MASK (LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | LIGHTBAR_WELCOME) + +static int uniwill_led_init(struct uniwill_data *data) +{ + struct led_init_data init_data = { + .devicename = DRIVER_NAME, + .default_label = "multicolor:" LED_FUNCTION_STATUS, + .devname_mandatory = true, + }; + unsigned int color_indices[3] = { + LED_COLOR_ID_RED, + LED_COLOR_ID_GREEN, + LED_COLOR_ID_BLUE, + }; + unsigned int value; + int ret; + + if (!(supported_features & UNIWILL_FEATURE_LIGHTBAR)) + return 0; + + ret = devm_mutex_init(data->dev, &data->led_lock); + if (ret < 0) + return ret; + + /* + * The EC has separate lightbar settings for AC and battery mode, + * so we have to ensure that both settings are the same. + */ + ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value); + if (ret < 0) + return ret; + + value |= LIGHTBAR_APP_EXISTS; + ret = regmap_write(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, value); + if (ret < 0) + return ret; + + /* + * The breathing animation during suspend is not supported when + * running on battery power. + */ + value |= LIGHTBAR_S3_OFF; + ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_MASK, value); + if (ret < 0) + return ret; + + data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI; + data->led_mc_cdev.led_cdev.max_brightness = LED_MAX_BRIGHTNESS; + data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT; + data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set; + + if (value & LIGHTBAR_S0_OFF) + data->led_mc_cdev.led_cdev.brightness = 0; + else + data->led_mc_cdev.led_cdev.brightness = LED_MAX_BRIGHTNESS; + + for (int i = 0; i < LED_CHANNELS; i++) { + data->led_mc_subled_info[i].color_index = color_indices[i]; + + ret = regmap_read(data->regmap, uniwill_led_channel_to_ac_reg[i], &value); + if (ret < 0) + return ret; + + /* + * Make sure that the initial intensity value is not greater than + * the maximum brightness. + */ + value = min(LED_MAX_BRIGHTNESS, value); + ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value); + if (ret < 0) + return ret; + + ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value); + if (ret < 0) + return ret; + + data->led_mc_subled_info[i].intensity = value; + data->led_mc_subled_info[i].channel = i; + } + + data->led_mc_cdev.subled_info = data->led_mc_subled_info; + data->led_mc_cdev.num_colors = LED_CHANNELS; + + return devm_led_classdev_multicolor_register_ext(data->dev, &data->led_mc_cdev, + &init_data); +} + +static int uniwill_get_property(struct power_supply *psy, const struct power_supply_ext *ext, + void *drvdata, enum power_supply_property psp, + union power_supply_propval *val) +{ + struct uniwill_data *data = drvdata; + union power_supply_propval prop; + unsigned int regval; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_HEALTH: + ret = power_supply_get_property_direct(psy, POWER_SUPPLY_PROP_PRESENT, &prop); + if (ret < 0) + return ret; + + if (!prop.intval) { + val->intval = POWER_SUPPLY_HEALTH_NO_BATTERY; + return 0; + } + + ret = power_supply_get_property_direct(psy, POWER_SUPPLY_PROP_STATUS, &prop); + if (ret < 0) + return ret; + + if (prop.intval == POWER_SUPPLY_STATUS_UNKNOWN) { + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; + return 0; + } + + ret = regmap_read(data->regmap, EC_ADDR_BAT_ALERT, ®val); + if (ret < 0) + return ret; + + if (regval) { + /* Charging issue */ + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + return 0; + } + + val->intval = POWER_SUPPLY_HEALTH_GOOD; + return 0; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + ret = regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, ®val); + if (ret < 0) + return ret; + + val->intval = clamp_val(FIELD_GET(CHARGE_CTRL_MASK, regval), 0, 100); + return 0; + default: + return -EINVAL; + } +} + +static int uniwill_set_property(struct power_supply *psy, const struct power_supply_ext *ext, + void *drvdata, enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct uniwill_data *data = drvdata; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + if (val->intval < 1 || val->intval > 100) + return -EINVAL; + + return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK, + val->intval); + default: + return -EINVAL; + } +} + +static int uniwill_property_is_writeable(struct power_supply *psy, + const struct power_supply_ext *ext, void *drvdata, + enum power_supply_property psp) +{ + if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) + return true; + + return false; +} + +static const enum power_supply_property uniwill_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, +}; + +static const struct power_supply_ext uniwill_extension = { + .name = DRIVER_NAME, + .properties = uniwill_properties, + .num_properties = ARRAY_SIZE(uniwill_properties), + .get_property = uniwill_get_property, + .set_property = uniwill_set_property, + .property_is_writeable = uniwill_property_is_writeable, +}; + +static int uniwill_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct uniwill_data *data = container_of(hook, struct uniwill_data, hook); + struct uniwill_battery_entry *entry; + int ret; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + ret = power_supply_register_extension(battery, &uniwill_extension, data->dev, data); + if (ret < 0) { + kfree(entry); + return ret; + } + + guard(mutex)(&data->battery_lock); + + entry->battery = battery; + list_add(&entry->head, &data->batteries); + + return 0; +} + +static int uniwill_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct uniwill_data *data = container_of(hook, struct uniwill_data, hook); + struct uniwill_battery_entry *entry, *tmp; + + scoped_guard(mutex, &data->battery_lock) { + list_for_each_entry_safe(entry, tmp, &data->batteries, head) { + if (entry->battery == battery) { + list_del(&entry->head); + kfree(entry); + break; + } + } + } + + power_supply_unregister_extension(battery, &uniwill_extension); + + return 0; +} + +static int uniwill_battery_init(struct uniwill_data *data) +{ + int ret; + + if (!(supported_features & UNIWILL_FEATURE_BATTERY)) + return 0; + + ret = devm_mutex_init(data->dev, &data->battery_lock); + if (ret < 0) + return ret; + + INIT_LIST_HEAD(&data->batteries); + data->hook.name = "Uniwill Battery Extension"; + data->hook.add_battery = uniwill_add_battery; + data->hook.remove_battery = uniwill_remove_battery; + + return devm_battery_hook_register(data->dev, &data->hook); +} + +static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action, void *dummy) +{ + struct uniwill_data *data = container_of(nb, struct uniwill_data, nb); + struct uniwill_battery_entry *entry; + + switch (action) { + case UNIWILL_OSD_BATTERY_ALERT: + mutex_lock(&data->battery_lock); + list_for_each_entry(entry, &data->batteries, head) { + power_supply_changed(entry->battery); + } + mutex_unlock(&data->battery_lock); + + return NOTIFY_OK; + case UNIWILL_OSD_DC_ADAPTER_CHANGED: + /* noop for the time being, will change once charging priority + * gets implemented. + */ + + return NOTIFY_OK; + default: + mutex_lock(&data->input_lock); + sparse_keymap_report_event(data->input_device, action, 1, true); + mutex_unlock(&data->input_lock); + + return NOTIFY_OK; + } +} + +static int uniwill_input_init(struct uniwill_data *data) +{ + int ret; + + ret = devm_mutex_init(data->dev, &data->input_lock); + if (ret < 0) + return ret; + + data->input_device = devm_input_allocate_device(data->dev); + if (!data->input_device) + return -ENOMEM; + + ret = sparse_keymap_setup(data->input_device, uniwill_keymap, NULL); + if (ret < 0) + return ret; + + data->input_device->name = "Uniwill WMI hotkeys"; + data->input_device->phys = "wmi/input0"; + data->input_device->id.bustype = BUS_HOST; + ret = input_register_device(data->input_device); + if (ret < 0) + return ret; + + data->nb.notifier_call = uniwill_notifier_call; + + return devm_uniwill_wmi_register_notifier(data->dev, &data->nb); +} + +static void uniwill_disable_manual_control(void *context) +{ + struct uniwill_data *data = context; + + regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL); +} + +static int uniwill_ec_init(struct uniwill_data *data) +{ + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value); + if (ret < 0) + return ret; + + dev_dbg(data->dev, "Project ID: %u\n", value); + + ret = regmap_set_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL); + if (ret < 0) + return ret; + + return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data); +} + +static int uniwill_probe(struct platform_device *pdev) +{ + struct uniwill_data *data; + struct regmap *regmap; + acpi_handle handle; + int ret; + + handle = ACPI_HANDLE(&pdev->dev); + if (!handle) + return -ENODEV; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &pdev->dev; + data->handle = handle; + platform_set_drvdata(pdev, data); + + regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, &uniwill_ec_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + data->regmap = regmap; + ret = devm_mutex_init(&pdev->dev, &data->super_key_lock); + if (ret < 0) + return ret; + + ret = uniwill_ec_init(data); + if (ret < 0) + return ret; + + ret = uniwill_battery_init(data); + if (ret < 0) + return ret; + + ret = uniwill_led_init(data); + if (ret < 0) + return ret; + + ret = uniwill_hwmon_init(data); + if (ret < 0) + return ret; + + return uniwill_input_init(data); +} + +static void uniwill_shutdown(struct platform_device *pdev) +{ + struct uniwill_data *data = platform_get_drvdata(pdev); + + regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL); +} + +static int uniwill_suspend_keyboard(struct uniwill_data *data) +{ + if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE)) + return 0; + + /* + * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to restore it + * ourselves. + */ + return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &data->last_switch_status); +} + +static int uniwill_suspend_battery(struct uniwill_data *data) +{ + if (!(supported_features & UNIWILL_FEATURE_BATTERY)) + return 0; + + /* + * Save the current charge limit in order to restore it during resume. + * We cannot use the regmap code for that since this register needs to + * be declared as volatile due to CHARGE_CTRL_REACHED. + */ + return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl); +} + +static int uniwill_suspend(struct device *dev) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + int ret; + + ret = uniwill_suspend_keyboard(data); + if (ret < 0) + return ret; + + ret = uniwill_suspend_battery(data); + if (ret < 0) + return ret; + + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + + return 0; +} + +static int uniwill_resume_keyboard(struct uniwill_data *data) +{ + unsigned int value; + int ret; + + if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE)) + return 0; + + ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value); + if (ret < 0) + return ret; + + if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & SUPER_KEY_LOCK_STATUS)) + return 0; + + return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK, + TRIGGER_SUPER_KEY_LOCK); +} + +static int uniwill_resume_battery(struct uniwill_data *data) +{ + if (!(supported_features & UNIWILL_FEATURE_BATTERY)) + return 0; + + return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK, + data->last_charge_ctrl); +} + +static int uniwill_resume(struct device *dev) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + int ret; + + regcache_cache_only(data->regmap, false); + + ret = regcache_sync(data->regmap); + if (ret < 0) + return ret; + + ret = uniwill_resume_keyboard(data); + if (ret < 0) + return ret; + + return uniwill_resume_battery(data); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume); + +/* + * We only use the DMI table for auoloading because the ACPI device itself + * does not guarantee that the underlying EC implementation is supported. + */ +static const struct acpi_device_id uniwill_id_table[] = { + { "INOU0000" }, + { }, +}; + +static struct platform_driver uniwill_driver = { + .driver = { + .name = DRIVER_NAME, + .dev_groups = uniwill_groups, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .acpi_match_table = uniwill_id_table, + .pm = pm_sleep_ptr(&uniwill_pm_ops), + }, + .probe = uniwill_probe, + .shutdown = uniwill_shutdown, +}; + +static const struct dmi_system_id uniwill_dmi_table[] __initconst = { + { + .ident = "XMG FUSION 15", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"), + }, + }, + { + .ident = "XMG FUSION 15", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"), + }, + }, + { + .ident = "Intel NUC x15", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPAC71H"), + }, + .driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE | + UNIWILL_FEATURE_SUPER_KEY_TOGGLE | + UNIWILL_FEATURE_TOUCHPAD_TOGGLE | + UNIWILL_FEATURE_BATTERY | + UNIWILL_FEATURE_HWMON), + }, + { + .ident = "Intel NUC x15", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPKC71F"), + }, + .driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE | + UNIWILL_FEATURE_SUPER_KEY_TOGGLE | + UNIWILL_FEATURE_TOUCHPAD_TOGGLE | + UNIWILL_FEATURE_LIGHTBAR | + UNIWILL_FEATURE_BATTERY | + UNIWILL_FEATURE_HWMON), + }, + { + .ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"), + }, + }, + { + .ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"), + }, + }, + { + .ident = "TUXEDO InfinityBook Max 15 Gen10 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"), + }, + }, + { + .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"), + }, + }, + { + .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"), + }, + }, + { + .ident = "TUXEDO InfinityBook Max 15 Gen10 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"), + }, + }, + { + .ident = "TUXEDO InfinityBook Max 16 Gen10 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"), + }, + }, + { + .ident = "TUXEDO Polaris 15 Gen1 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"), + }, + }, + { + .ident = "TUXEDO Polaris 15 Gen1 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"), + }, + }, + { + .ident = "TUXEDO Polaris 17 Gen1 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"), + }, + }, + { + .ident = "TUXEDO Polaris 17 Gen1 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"), + }, + }, + { + .ident = "TUXEDO Polaris 15 Gen1 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"), + }, + }, + { + .ident = "TUXEDO Polaris 15 Gen1 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"), + }, + }, + { + .ident = "TUXEDO Polaris 17 Gen1 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"), + }, + }, + { + .ident = "TUXEDO Polaris 17 Gen1 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"), + }, + }, + { + .ident = "TUXEDO Trinity 15 Intel Gen1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"), + }, + }, + { + .ident = "TUXEDO Trinity 17 Intel Gen1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"), + }, + }, + { + .ident = "TUXEDO Polaris 15/17 Gen2 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"), + }, + }, + { + .ident = "TUXEDO Polaris 15/17 Gen2 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"), + }, + }, + { + .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"), + }, + }, + { + .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"), + }, + }, + { + .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"), + }, + }, + { + .ident = "TUXEDO Stellaris 15 Gen4 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"), + }, + }, + { + .ident = "TUXEDO Polaris 15/17 Gen5 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"), + }, + }, + { + .ident = "TUXEDO Stellaris 16 Gen5 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"), + }, + }, + { + .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"), + }, + }, + { + .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"), + }, + }, + { + .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"), + }, + }, + { + .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"), + }, + }, + { + .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"), + }, + }, + { + .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"), + }, + }, + { + .ident = "TUXEDO Stellaris 16 Gen7 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"), + }, + }, + { + .ident = "TUXEDO Stellaris 16 Gen7 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"), + }, + }, + { + .ident = "TUXEDO Stellaris 16 Gen7 Intel", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"), + }, + }, + { + .ident = "TUXEDO Pulse 14 Gen1 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"), + }, + }, + { + .ident = "TUXEDO Pulse 15 Gen1 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"), + }, + }, + { + .ident = "TUXEDO Pulse 15 Gen2 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"), + }, + }, + { } +}; +MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table); + +static int __init uniwill_init(void) +{ + const struct dmi_system_id *id; + int ret; + + id = dmi_first_match(uniwill_dmi_table); + if (!id) { + if (!force) + return -ENODEV; + + /* Assume that the device supports all features */ + supported_features = UINT_MAX; + pr_warn("Loading on a potentially unsupported device\n"); + } else { + supported_features = (uintptr_t)id->driver_data; + } + + ret = platform_driver_register(&uniwill_driver); + if (ret < 0) + return ret; + + ret = uniwill_wmi_register_driver(); + if (ret < 0) { + platform_driver_unregister(&uniwill_driver); + return ret; + } + + return 0; +} +module_init(uniwill_init); + +static void __exit uniwill_exit(void) +{ + uniwill_wmi_unregister_driver(); + platform_driver_unregister(&uniwill_driver); +} +module_exit(uniwill_exit); + +MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>"); +MODULE_DESCRIPTION("Uniwill notebook driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.c b/drivers/platform/x86/uniwill/uniwill-wmi.c new file mode 100644 index 000000000000..31d9c39f14ab --- /dev/null +++ b/drivers/platform/x86/uniwill/uniwill-wmi.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Linux hotkey driver for Uniwill notebooks. + * + * Special thanks go to PÅ‘cze Barnabás, Christoffer Sandberg and Werner Sembach + * for supporting the development of this driver either through prior work or + * by answering questions regarding the underlying WMI interface. + * + * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/acpi.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/mod_devicetable.h> +#include <linux/notifier.h> +#include <linux/printk.h> +#include <linux/types.h> +#include <linux/wmi.h> + +#include "uniwill-wmi.h" + +#define DRIVER_NAME "uniwill-wmi" +#define UNIWILL_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" + +static BLOCKING_NOTIFIER_HEAD(uniwill_wmi_chain_head); + +static void devm_uniwill_wmi_unregister_notifier(void *data) +{ + struct notifier_block *nb = data; + + blocking_notifier_chain_unregister(&uniwill_wmi_chain_head, nb); +} + +int devm_uniwill_wmi_register_notifier(struct device *dev, struct notifier_block *nb) +{ + int ret; + + ret = blocking_notifier_chain_register(&uniwill_wmi_chain_head, nb); + if (ret < 0) + return ret; + + return devm_add_action_or_reset(dev, devm_uniwill_wmi_unregister_notifier, nb); +} + +static void uniwill_wmi_notify(struct wmi_device *wdev, union acpi_object *obj) +{ + u32 value; + + if (obj->type != ACPI_TYPE_INTEGER) + return; + + value = obj->integer.value; + + dev_dbg(&wdev->dev, "Received WMI event %u\n", value); + + blocking_notifier_call_chain(&uniwill_wmi_chain_head, value, NULL); +} + +/* + * We cannot fully trust this GUID since Uniwill just copied the WMI GUID + * from the Windows driver example, and others probably did the same. + * + * Because of this we cannot use this WMI GUID for autoloading. Instead the + * associated driver will be registered manually after matching a DMI table. + */ +static const struct wmi_device_id uniwill_wmi_id_table[] = { + { UNIWILL_EVENT_GUID, NULL }, + { } +}; + +static struct wmi_driver uniwill_wmi_driver = { + .driver = { + .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table = uniwill_wmi_id_table, + .notify = uniwill_wmi_notify, + .no_singleton = true, +}; + +int __init uniwill_wmi_register_driver(void) +{ + return wmi_driver_register(&uniwill_wmi_driver); +} + +void __exit uniwill_wmi_unregister_driver(void) +{ + wmi_driver_unregister(&uniwill_wmi_driver); +} diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h new file mode 100644 index 000000000000..48783b2e9ffb --- /dev/null +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Linux hotkey driver for Uniwill notebooks. + * + * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de> + */ + +#ifndef UNIWILL_WMI_H +#define UNIWILL_WMI_H + +#include <linux/init.h> + +#define UNIWILL_OSD_CAPSLOCK 0x01 +#define UNIWILL_OSD_NUMLOCK 0x02 +#define UNIWILL_OSD_SCROLLLOCK 0x03 + +#define UNIWILL_OSD_TOUCHPAD_ON 0x04 +#define UNIWILL_OSD_TOUCHPAD_OFF 0x05 + +#define UNIWILL_OSD_SILENT_MODE_ON 0x06 +#define UNIWILL_OSD_SILENT_MODE_OFF 0x07 + +#define UNIWILL_OSD_WLAN_ON 0x08 +#define UNIWILL_OSD_WLAN_OFF 0x09 + +#define UNIWILL_OSD_WIMAX_ON 0x0A +#define UNIWILL_OSD_WIMAX_OFF 0x0B + +#define UNIWILL_OSD_BLUETOOTH_ON 0x0C +#define UNIWILL_OSD_BLUETOOTH_OFF 0x0D + +#define UNIWILL_OSD_RF_ON 0x0E +#define UNIWILL_OSD_RF_OFF 0x0F + +#define UNIWILL_OSD_3G_ON 0x10 +#define UNIWILL_OSD_3G_OFF 0x11 + +#define UNIWILL_OSD_WEBCAM_ON 0x12 +#define UNIWILL_OSD_WEBCAM_OFF 0x13 + +#define UNIWILL_OSD_BRIGHTNESSUP 0x14 +#define UNIWILL_OSD_BRIGHTNESSDOWN 0x15 + +#define UNIWILL_OSD_RADIOON 0x1A +#define UNIWILL_OSD_RADIOOFF 0x1B + +#define UNIWILL_OSD_POWERSAVE_ON 0x31 +#define UNIWILL_OSD_POWERSAVE_OFF 0x32 + +#define UNIWILL_OSD_MENU 0x34 + +#define UNIWILL_OSD_MUTE 0x35 +#define UNIWILL_OSD_VOLUMEDOWN 0x36 +#define UNIWILL_OSD_VOLUMEUP 0x37 + +#define UNIWILL_OSD_MENU_2 0x38 + +#define UNIWILL_OSD_LIGHTBAR_ON 0x39 +#define UNIWILL_OSD_LIGHTBAR_OFF 0x3A + +#define UNIWILL_OSD_KB_LED_LEVEL0 0x3B +#define UNIWILL_OSD_KB_LED_LEVEL1 0x3C +#define UNIWILL_OSD_KB_LED_LEVEL2 0x3D +#define UNIWILL_OSD_KB_LED_LEVEL3 0x3E +#define UNIWILL_OSD_KB_LED_LEVEL4 0x3F + +#define UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE 0x40 +#define UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE 0x41 + +#define UNIWILL_OSD_MENU_JP 0x42 + +#define UNIWILL_OSD_CAMERA_ON 0x90 +#define UNIWILL_OSD_CAMERA_OFF 0x91 + +#define UNIWILL_OSD_RFKILL 0xA4 + +#define UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED 0xA5 + +#define UNIWILL_OSD_LIGHTBAR_STATE_CHANGED 0xA6 + +#define UNIWILL_OSD_FAN_BOOST_STATE_CHANGED 0xA7 + +#define UNIWILL_OSD_LCD_SW 0xA9 + +#define UNIWILL_OSD_FAN_OVERTEMP 0xAA + +#define UNIWILL_OSD_DC_ADAPTER_CHANGED 0xAB + +#define UNIWILL_OSD_BAT_HP_OFF 0xAC + +#define UNIWILL_OSD_FAN_DOWN_TEMP 0xAD + +#define UNIWILL_OSD_BATTERY_ALERT 0xAE + +#define UNIWILL_OSD_TIMAP_HAIERLB_SW 0xAF + +#define UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE 0xB0 + +#define UNIWILL_OSD_KBDILLUMDOWN 0xB1 +#define UNIWILL_OSD_KBDILLUMUP 0xB2 + +#define UNIWILL_OSD_BACKLIGHT_LEVEL_CHANGE 0xB3 +#define UNIWILL_OSD_BACKLIGHT_POWER_CHANGE 0xB4 + +#define UNIWILL_OSD_MIC_MUTE 0xB7 + +#define UNIWILL_OSD_FN_LOCK 0xB8 +#define UNIWILL_OSD_KBDILLUMTOGGLE 0xB9 + +#define UNIWILL_OSD_BAT_CHARGE_FULL_24_H 0xBE + +#define UNIWILL_OSD_BAT_ERM_UPDATE 0xBF + +#define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0 + +#define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF + +#define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0 + +struct device; +struct notifier_block; + +int devm_uniwill_wmi_register_notifier(struct device *dev, struct notifier_block *nb); + +int __init uniwill_wmi_register_driver(void); + +void __exit uniwill_wmi_unregister_driver(void); + +#endif /* UNIWILL_WMI_H */ diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index e3d3a8290949..8d825e0b4661 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -543,7 +543,7 @@ static int __init lenovo_yoga_tab2_830_1050_init_codec(void) ret = device_add_software_node(codec_dev, &lenovo_yoga_tab2_830_1050_wm5102); if (ret) { - ret = dev_err_probe(codec_dev, ret, "adding software node\n"); + dev_err_probe(codec_dev, ret, "adding software node\n"); goto err_put_pinctrl; } diff --git a/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c b/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c index 2f8cd8d9e0ab..ebbedfe5f4e8 100644 --- a/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c +++ b/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c @@ -183,7 +183,7 @@ static void atla10_ec_external_power_changed(struct power_supply *psy) struct atla10_ec_data *data = power_supply_get_drvdata(psy); /* After charger plug in/out wait 0.5s for things to stabilize */ - mod_delayed_work(system_wq, &data->work, HZ / 2); + mod_delayed_work(system_percpu_wq, &data->work, HZ / 2); } static const enum power_supply_property atla10_ec_psy_props[] = { diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index bf2d101f67a1..6f3147518376 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -760,7 +760,9 @@ config PWM_TEGRA config PWM_TH1520 tristate "TH1520 PWM support" + depends on ARCH_THEAD || COMPILE_TEST depends on RUST + depends on HAS_IOMEM && COMMON_CLK select RUST_PWM_ABSTRACTIONS help This option enables the driver for the PWM controller found on the diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f4987f54e01b..4b6182cde859 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2823,14 +2823,18 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) { struct regulator_enable_gpio *pin = rdev->ena_pin; + int ret; if (!pin) return -EINVAL; if (enable) { /* Enable GPIO at initial use */ - if (pin->enable_count == 0) - gpiod_set_value_cansleep(pin->gpiod, 1); + if (pin->enable_count == 0) { + ret = gpiod_set_value_cansleep(pin->gpiod, 1); + if (ret) + return ret; + } pin->enable_count++; } else { @@ -2841,7 +2845,10 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) /* Disable GPIO if not used */ if (pin->enable_count <= 1) { - gpiod_set_value_cansleep(pin->gpiod, 0); + ret = gpiod_set_value_cansleep(pin->gpiod, 0); + if (ret) + return ret; + pin->enable_count = 0; } } diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index a2d16e9abfb5..254c0a8a4555 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -330,13 +330,10 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc, &cfg); - if (IS_ERR(drvdata->dev)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev), - "Failed to register regulator: %ld\n", - PTR_ERR(drvdata->dev)); - gpiod_put(cfg.ena_gpiod); - return ret; - } + if (IS_ERR(drvdata->dev)) + return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev), + "Failed to register regulator: %ld\n", + PTR_ERR(drvdata->dev)); platform_set_drvdata(pdev, drvdata); diff --git a/drivers/regulator/spacemit-p1.c b/drivers/regulator/spacemit-p1.c index d437e6738ea1..2bf9137e12b1 100644 --- a/drivers/regulator/spacemit-p1.c +++ b/drivers/regulator/spacemit-p1.c @@ -87,10 +87,10 @@ static const struct linear_range p1_ldo_ranges[] = { } #define P1_BUCK_DESC(_n) \ - P1_REG_DESC(BUCK, buck, _n, "vcc", 0x47, BUCK_MASK, 254, p1_buck_ranges) + P1_REG_DESC(BUCK, buck, _n, "vin", 0x47, BUCK_MASK, 254, p1_buck_ranges) #define P1_ALDO_DESC(_n) \ - P1_REG_DESC(ALDO, aldo, _n, "vcc", 0x5b, LDO_MASK, 117, p1_ldo_ranges) + P1_REG_DESC(ALDO, aldo, _n, "vin", 0x5b, LDO_MASK, 117, p1_ldo_ranges) #define P1_DLDO_DESC(_n) \ P1_REG_DESC(DLDO, dldo, _n, "buck5", 0x67, LDO_MASK, 117, p1_ldo_ranges) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2933c41c77c8..50dc779f7f98 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -409,13 +409,22 @@ config RTC_DRV_MAX77686 config RTC_DRV_SPACEMIT_P1 tristate "SpacemiT P1 RTC" depends on ARCH_SPACEMIT || COMPILE_TEST - select MFD_SPACEMIT_P1 - default ARCH_SPACEMIT + depends on MFD_SPACEMIT_P1 + default MFD_SPACEMIT_P1 help Enable support for the RTC function in the SpacemiT P1 PMIC. This driver can also be built as a module, which will be called "spacemit-p1-rtc". +config RTC_DRV_NVIDIA_VRS10 + tristate "NVIDIA VRS10 RTC device" + help + If you say yes here you will get support for the battery backed RTC device + of NVIDIA VRS (Voltage Regulator Specification). The RTC is connected via + I2C interface and supports alarm functionality. + This driver can also be built as a module. If so, the module will be called + rtc-nvidia-vrs10. + config RTC_DRV_NCT3018Y tristate "Nuvoton NCT3018Y" depends on OF @@ -1063,6 +1072,21 @@ config RTC_DRV_ALPHA Direct support for the real-time clock found on every Alpha system, specifically MC146818 compatibles. If in doubt, say Y. +config RTC_DRV_ATCRTC100 + tristate "Andes ATCRTC100" + depends on ARCH_ANDES || COMPILE_TEST + select REGMAP_MMIO + help + If you say yes here you will get support for the Andes ATCRTC100 + RTC driver. + + This driver provides support for the Andes ATCRTC100 real-time clock + device. It allows setting and retrieving the time and date, as well + as setting alarms. + + To compile this driver as a module, choose M here: the module will + be called rtc-atcrtc100. + config RTC_DRV_DS1216 tristate "Dallas DS1216" depends on SNI_RM @@ -1749,7 +1773,7 @@ config RTC_DRV_MC13XXX tristate "Freescale MC13xxx RTC" help This enables support for the RTCs found on Freescale's PMICs - MC13783 and MC13892. + MC13783, MC13892 and MC34708. config RTC_DRV_MPC5121 tristate "Freescale MPC5121 built-in RTC" @@ -2074,6 +2098,17 @@ config RTC_DRV_WILCO_EC This can also be built as a module. If so, the module will be named "rtc_wilco_ec". +config RTC_DRV_MACSMC + tristate "Apple Mac System Management Controller RTC" + depends on MFD_MACSMC + help + If you say yes here you get support for RTC functions + inside Apple SPMI PMUs accessed through the SoC's + System Management Controller + + To compile this driver as a module, choose M here: the + module will be called rtc-macsmc. + config RTC_DRV_MSC313 tristate "MStar MSC313 RTC" depends on ARCH_MSTARV7 || COMPILE_TEST diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 8221bda6e6dc..6cf7e066314e 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o +obj-$(CONFIG_RTC_DRV_ATCRTC100) += rtc-atcrtc100.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o @@ -93,6 +94,7 @@ obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_MA35D1) += rtc-ma35d1.o +obj-$(CONFIG_RTC_DRV_MACSMC) += rtc-macsmc.o obj-$(CONFIG_RTC_DRV_MAX31335) += rtc-max31335.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o @@ -121,6 +123,7 @@ obj-$(CONFIG_RTC_DRV_GAMECUBE) += rtc-gamecube.o obj-$(CONFIG_RTC_DRV_NCT3018Y) += rtc-nct3018y.o obj-$(CONFIG_RTC_DRV_NCT6694) += rtc-nct6694.o obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o +obj-$(CONFIG_RTC_DRV_NVIDIA_VRS10)+= rtc-nvidia-vrs10.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o obj-$(CONFIG_RTC_DRV_OPTEE) += rtc-optee.o diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c index 1928b29c1045..123fb372fc9f 100644 --- a/drivers/rtc/rtc-amlogic-a4.c +++ b/drivers/rtc/rtc-amlogic-a4.c @@ -361,39 +361,26 @@ static int aml_rtc_probe(struct platform_device *pdev) "failed to get_enable rtc sys clk\n"); aml_rtc_init(rtc); - device_init_wakeup(dev, true); + devm_device_init_wakeup(dev); platform_set_drvdata(pdev, rtc); rtc->rtc_dev = devm_rtc_allocate_device(dev); - if (IS_ERR(rtc->rtc_dev)) { - ret = PTR_ERR(rtc->rtc_dev); - goto err_clk; - } + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler, IRQF_ONESHOT, "aml-rtc alarm", rtc); if (ret) { dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n", rtc->irq, ret); - goto err_clk; + return ret; } rtc->rtc_dev->ops = &aml_rtc_ops; rtc->rtc_dev->range_min = 0; rtc->rtc_dev->range_max = U32_MAX; - ret = devm_rtc_register_device(rtc->rtc_dev); - if (ret) { - dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret); - goto err_clk; - } - - return 0; -err_clk: - clk_disable_unprepare(rtc->sys_clk); - device_init_wakeup(dev, false); - - return ret; + return devm_rtc_register_device(rtc->rtc_dev); } #ifdef CONFIG_PM_SLEEP @@ -421,14 +408,6 @@ static int aml_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops, aml_rtc_suspend, aml_rtc_resume); -static void aml_rtc_remove(struct platform_device *pdev) -{ - struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(rtc->sys_clk); - device_init_wakeup(&pdev->dev, false); -} - static const struct aml_rtc_config a5_rtc_config = { }; @@ -451,7 +430,6 @@ MODULE_DEVICE_TABLE(of, aml_rtc_device_id); static struct platform_driver aml_rtc_driver = { .probe = aml_rtc_probe, - .remove = aml_rtc_remove, .driver = { .name = "aml-rtc", .pm = &aml_rtc_pm_ops, diff --git a/drivers/rtc/rtc-atcrtc100.c b/drivers/rtc/rtc-atcrtc100.c new file mode 100644 index 000000000000..9808fc2c5a49 --- /dev/null +++ b/drivers/rtc/rtc-atcrtc100.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Andes ATCRTC100 real time clock. + * + * Copyright (C) 2025 Andes Technology Corporation + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/workqueue.h> + +/* Register Offsets */ +#define RTC_ID 0x00 /* ID and Revision Register */ +#define RTC_RSV 0x04 /* Reserved Register */ +#define RTC_CNT 0x10 /* Counter Register */ +#define RTC_ALM 0x14 /* Alarm Register */ +#define RTC_CR 0x18 /* Control Register */ +#define RTC_STA 0x1C /* Status Register */ +#define RTC_TRIM 0x20 /* Digital Trimming Register */ + +/* RTC_ID Register */ +#define ID_MSK GENMASK(31, 8) +#define ID_ATCRTC100 0x030110 + +/* RTC_CNT and RTC_ALM Register Fields */ +#define SEC_MSK GENMASK(5, 0) +#define MIN_MSK GENMASK(11, 6) +#define HOUR_MSK GENMASK(16, 12) +#define DAY_MSK GENMASK(31, 17) +#define RTC_SEC_GET(x) FIELD_GET(SEC_MSK, x) +#define RTC_MIN_GET(x) FIELD_GET(MIN_MSK, x) +#define RTC_HOUR_GET(x) FIELD_GET(HOUR_MSK, x) +#define RTC_DAY_GET(x) FIELD_GET(DAY_MSK, x) +#define RTC_SEC_SET(x) FIELD_PREP(SEC_MSK, x) +#define RTC_MIN_SET(x) FIELD_PREP(MIN_MSK, x) +#define RTC_HOUR_SET(x) FIELD_PREP(HOUR_MSK, x) +#define RTC_DAY_SET(x) FIELD_PREP(DAY_MSK, x) + +/* RTC_CR Register Bits */ +#define RTC_EN BIT(0) /* RTC Enable */ +#define ALARM_WAKEUP BIT(1) /* Alarm Wakeup Enable */ +#define ALARM_INT BIT(2) /* Alarm Interrupt Enable */ +#define DAY_INT BIT(3) /* Day Interrupt Enable */ +#define HOUR_INT BIT(4) /* Hour Interrupt Enable */ +#define MIN_INT BIT(5) /* Minute Interrupt Enable */ +#define SEC_INT BIT(6) /* Second Periodic Interrupt Enable */ +#define HSEC_INT BIT(7) /* Half-Second Periodic Interrupt Enable */ + +/* RTC_STA Register Bits */ +#define WRITE_DONE BIT(16) /* Register write completion status */ + +/* Time conversion macro */ +#define ATCRTC_TIME_TO_SEC(D, H, M, S) \ + ((time64_t)(D) * 86400 + (H) * 3600 + (M) * 60 + (S)) + +/* Timeout for waiting for the write_done bit */ +#define ATCRTC_TIMEOUT_US 1000000 +#define ATCRTC_TIMEOUT_USLEEP_MIN 20 +#define ATCRTC_TIMEOUT_USLEEP_MAX 30 + +struct atcrtc_dev { + struct rtc_device *rtc_dev; + struct regmap *regmap; + struct work_struct rtc_work; + unsigned int alarm_irq; + bool alarm_en; +}; + +static const struct regmap_config atcrtc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = RTC_TRIM, + .cache_type = REGCACHE_NONE, +}; + +/** + * atcrtc_check_write_done - Wait for RTC registers to be synchronized. + * @rtc: Pointer to the atcrtc_dev structure. + * + * The WriteDone bit in the status register indicates the synchronization + * progress of RTC register updates. This bit is cleared to zero whenever + * any RTC control register (Counter, Alarm, Control, etc.) is written. + * It returns to one only after all previous updates have been fully + * synchronized to the RTC clock domain. This function polls the WriteDone + * bit with a timeout to ensure the device is ready for the next operation. + * + * Return: 0 on success, or -EBUSY on timeout. + */ +static int atcrtc_check_write_done(struct atcrtc_dev *rtc) +{ + unsigned int val; + + /* + * Using read_poll_timeout is more efficient than a manual loop + * with usleep_range. + */ + return regmap_read_poll_timeout(rtc->regmap, RTC_STA, val, + val & WRITE_DONE, + ATCRTC_TIMEOUT_USLEEP_MIN, + ATCRTC_TIMEOUT_US); +} + +static irqreturn_t atcrtc_alarm_isr(int irq, void *dev) +{ + struct atcrtc_dev *rtc = dev; + unsigned int status; + + regmap_read(rtc->regmap, RTC_STA, &status); + if (status & ALARM_INT) { + regmap_write(rtc->regmap, RTC_STA, ALARM_INT); + rtc->alarm_en = false; + schedule_work(&rtc->rtc_work); + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int atcrtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + unsigned int mask; + int ret; + + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + + mask = ALARM_WAKEUP | ALARM_INT; + regmap_update_bits(rtc->regmap, RTC_CR, mask, enable ? mask : 0); + + return 0; +} + +static void atcrtc_alarm_clear(struct work_struct *work) +{ + struct atcrtc_dev *rtc = + container_of(work, struct atcrtc_dev, rtc_work); + int ret; + + rtc_lock(rtc->rtc_dev); + + if (!rtc->alarm_en) { + ret = atcrtc_check_write_done(rtc); + if (ret) + dev_info(&rtc->rtc_dev->dev, + "failed to sync before clearing alarm: %d\n", + ret); + else + regmap_update_bits(rtc->regmap, RTC_CR, + ALARM_WAKEUP | ALARM_INT, 0); + } + rtc_unlock(rtc->rtc_dev); +} + +static int atcrtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + time64_t time; + unsigned int rtc_cnt; + + if (!regmap_test_bits(rtc->regmap, RTC_CR, RTC_EN)) + return -EIO; + + regmap_read(rtc->regmap, RTC_CNT, &rtc_cnt); + time = ATCRTC_TIME_TO_SEC(RTC_DAY_GET(rtc_cnt), + RTC_HOUR_GET(rtc_cnt), + RTC_MIN_GET(rtc_cnt), + RTC_SEC_GET(rtc_cnt)); + rtc_time64_to_tm(time, tm); + + return 0; +} + +static int atcrtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + time64_t time; + unsigned int counter; + unsigned int day; + int ret; + + time = rtc_tm_to_time64(tm); + day = div_s64(time, 86400); + counter = RTC_DAY_SET(day) | + RTC_HOUR_SET(tm->tm_hour) | + RTC_MIN_SET(tm->tm_min) | + RTC_SEC_SET(tm->tm_sec); + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + regmap_write(rtc->regmap, RTC_CNT, counter); + + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + regmap_update_bits(rtc->regmap, RTC_CR, RTC_EN, RTC_EN); + + return 0; +} + +static int atcrtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + unsigned int rtc_alarm; + + wkalrm->enabled = regmap_test_bits(rtc->regmap, RTC_CR, ALARM_INT); + regmap_read(rtc->regmap, RTC_ALM, &rtc_alarm); + tm->tm_hour = RTC_HOUR_GET(rtc_alarm); + tm->tm_min = RTC_MIN_GET(rtc_alarm); + tm->tm_sec = RTC_SEC_GET(rtc_alarm); + + /* The RTC alarm does not support day/month/year fields */ + tm->tm_mday = -1; + tm->tm_mon = -1; + tm->tm_year = -1; + + return 0; +} + +static int atcrtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + unsigned int rtc_alarm; + int ret; + + /* Disable alarm first before setting a new one */ + ret = atcrtc_alarm_irq_enable(dev, 0); + if (ret) + return ret; + + rtc->alarm_en = false; + + rtc_alarm = RTC_SEC_SET(tm->tm_sec) | + RTC_MIN_SET(tm->tm_min) | + RTC_HOUR_SET(tm->tm_hour); + + ret = atcrtc_check_write_done(rtc); + if (ret) + return ret; + + regmap_write(rtc->regmap, RTC_ALM, rtc_alarm); + + rtc->alarm_en = wkalrm->enabled; + ret = atcrtc_alarm_irq_enable(dev, wkalrm->enabled); + + return ret; +} + +static const struct rtc_class_ops rtc_ops = { + .read_time = atcrtc_read_time, + .set_time = atcrtc_set_time, + .read_alarm = atcrtc_read_alarm, + .set_alarm = atcrtc_set_alarm, + .alarm_irq_enable = atcrtc_alarm_irq_enable, +}; + +static int atcrtc_probe(struct platform_device *pdev) +{ + struct atcrtc_dev *atcrtc_dev; + void __iomem *reg_base; + unsigned int rtc_id; + int ret; + + atcrtc_dev = devm_kzalloc(&pdev->dev, sizeof(*atcrtc_dev), GFP_KERNEL); + if (!atcrtc_dev) + return -ENOMEM; + platform_set_drvdata(pdev, atcrtc_dev); + + reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg_base)) + return dev_err_probe(&pdev->dev, PTR_ERR(reg_base), + "Failed to map I/O space\n"); + + atcrtc_dev->regmap = devm_regmap_init_mmio(&pdev->dev, + reg_base, + &atcrtc_regmap_config); + if (IS_ERR(atcrtc_dev->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->regmap), + "Failed to initialize regmap\n"); + + regmap_read(atcrtc_dev->regmap, RTC_ID, &rtc_id); + if (FIELD_GET(ID_MSK, rtc_id) != ID_ATCRTC100) + return dev_err_probe(&pdev->dev, -ENODEV, + "Failed to initialize RTC: unsupported hardware ID 0x%x\n", + rtc_id); + + ret = platform_get_irq(pdev, 1); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to get IRQ for alarm\n"); + atcrtc_dev->alarm_irq = ret; + + ret = devm_request_irq(&pdev->dev, + atcrtc_dev->alarm_irq, + atcrtc_alarm_isr, + 0, + "atcrtc_alarm", + atcrtc_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to request IRQ %d for alarm\n", + atcrtc_dev->alarm_irq); + + atcrtc_dev->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(atcrtc_dev->rtc_dev)) + return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->rtc_dev), + "Failed to allocate RTC device\n"); + + set_bit(RTC_FEATURE_ALARM, atcrtc_dev->rtc_dev->features); + ret = device_init_wakeup(&pdev->dev, true); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to initialize wake capability\n"); + + ret = dev_pm_set_wake_irq(&pdev->dev, atcrtc_dev->alarm_irq); + if (ret) { + device_init_wakeup(&pdev->dev, false); + return dev_err_probe(&pdev->dev, ret, + "Failed to set wake IRQ\n"); + } + + atcrtc_dev->rtc_dev->ops = &rtc_ops; + + INIT_WORK(&atcrtc_dev->rtc_work, atcrtc_alarm_clear); + return devm_rtc_register_device(atcrtc_dev->rtc_dev); +} + +static int atcrtc_resume(struct device *dev) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->alarm_irq); + + return 0; +} + +static int atcrtc_suspend(struct device *dev) +{ + struct atcrtc_dev *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->alarm_irq); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(atcrtc_pm_ops, atcrtc_suspend, atcrtc_resume); + +static const struct of_device_id atcrtc_dt_match[] = { + { .compatible = "andestech,atcrtc100" }, + { }, +}; +MODULE_DEVICE_TABLE(of, atcrtc_dt_match); + +static struct platform_driver atcrtc_platform_driver = { + .driver = { + .name = "atcrtc100", + .of_match_table = atcrtc_dt_match, + .pm = pm_sleep_ptr(&atcrtc_pm_ops), + }, + .probe = atcrtc_probe, +}; + +module_platform_driver(atcrtc_platform_driver); + +MODULE_AUTHOR("CL Wang <cl634@andestech.com>"); +MODULE_DESCRIPTION("Andes ATCRTC100 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 97423f1d0361..5fc8e36b1abf 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1268,9 +1268,6 @@ ds1685_rtc_probe(struct platform_device *pdev) rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc_dev->range_max = RTC_TIMESTAMP_END_2099; - /* Maximum periodic rate is 8192Hz (0.122070ms). */ - rtc_dev->max_user_freq = RTC_MAX_USER_FREQ; - /* See if the platform doesn't support UIE. */ if (pdata->uie_unsupported) clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc_dev->features); diff --git a/drivers/rtc/rtc-gamecube.c b/drivers/rtc/rtc-gamecube.c index c828bc8e05b9..045d5d45ab4b 100644 --- a/drivers/rtc/rtc-gamecube.c +++ b/drivers/rtc/rtc-gamecube.c @@ -242,6 +242,10 @@ static int gamecube_rtc_read_offset_from_sram(struct priv *d) } hw_srnprot = ioremap(res.start, resource_size(&res)); + if (!hw_srnprot) { + pr_err("failed to ioremap hw_srnprot\n"); + return -ENOMEM; + } old = ioread32be(hw_srnprot); /* TODO: figure out why we use this magic constant. I obtained it by diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 2aabb9151d4c..45a2c9f676c5 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -484,6 +484,12 @@ static const struct of_device_id isl12026_dt_match[] = { }; MODULE_DEVICE_TABLE(of, isl12026_dt_match); +static const struct i2c_device_id isl12026_id[] = { + { "isl12026" }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, isl12026_id); + static struct i2c_driver isl12026_driver = { .driver = { .name = "rtc-isl12026", @@ -491,6 +497,7 @@ static struct i2c_driver isl12026_driver = { }, .probe = isl12026_probe, .remove = isl12026_remove, + .id_table = isl12026_id, }; module_i2c_driver(isl12026_driver); diff --git a/drivers/rtc/rtc-macsmc.c b/drivers/rtc/rtc-macsmc.c new file mode 100644 index 000000000000..8fe883066956 --- /dev/null +++ b/drivers/rtc/rtc-macsmc.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SMC RTC driver + * Copyright The Asahi Linux Contributors + */ + +#include <linux/bitops.h> +#include <linux/mfd/macsmc.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/slab.h> + +/* 48-bit RTC */ +#define RTC_BYTES 6 +#define RTC_BITS (8 * RTC_BYTES) + +/* 32768 Hz clock */ +#define RTC_SEC_SHIFT 15 + +struct macsmc_rtc { + struct device *dev; + struct apple_smc *smc; + struct rtc_device *rtc_dev; + struct nvmem_cell *rtc_offset; +}; + +static int macsmc_rtc_get_time(struct device *dev, struct rtc_time *tm) +{ + struct macsmc_rtc *rtc = dev_get_drvdata(dev); + u64 ctr = 0, off = 0; + time64_t now; + void *p_off; + size_t len; + int ret; + + ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES); + if (ret < 0) + return ret; + if (ret != RTC_BYTES) + return -EIO; + + p_off = nvmem_cell_read(rtc->rtc_offset, &len); + if (IS_ERR(p_off)) + return PTR_ERR(p_off); + if (len < RTC_BYTES) { + kfree(p_off); + return -EIO; + } + + memcpy(&off, p_off, RTC_BYTES); + kfree(p_off); + + /* Sign extend from 48 to 64 bits, then arithmetic shift right 15 bits to get seconds */ + now = sign_extend64(ctr + off, RTC_BITS - 1) >> RTC_SEC_SHIFT; + rtc_time64_to_tm(now, tm); + + return ret; +} + +static int macsmc_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct macsmc_rtc *rtc = dev_get_drvdata(dev); + u64 ctr = 0, off = 0; + int ret; + + ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES); + if (ret < 0) + return ret; + if (ret != RTC_BYTES) + return -EIO; + + /* This sets the offset such that the set second begins now */ + off = (rtc_tm_to_time64(tm) << RTC_SEC_SHIFT) - ctr; + return nvmem_cell_write(rtc->rtc_offset, &off, RTC_BYTES); +} + +static const struct rtc_class_ops macsmc_rtc_ops = { + .read_time = macsmc_rtc_get_time, + .set_time = macsmc_rtc_set_time, +}; + +static int macsmc_rtc_probe(struct platform_device *pdev) +{ + struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); + struct macsmc_rtc *rtc; + + /* + * MFD will probe this device even without a node in the device tree, + * thus bail out early if the SMC on the current machines does not + * support RTC and has no node in the device tree. + */ + if (!pdev->dev.of_node) + return -ENODEV; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->dev = &pdev->dev; + rtc->smc = smc; + + rtc->rtc_offset = devm_nvmem_cell_get(&pdev->dev, "rtc_offset"); + if (IS_ERR(rtc->rtc_offset)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_offset), + "Failed to get rtc_offset NVMEM cell\n"); + + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + + rtc->rtc_dev->ops = &macsmc_rtc_ops; + rtc->rtc_dev->range_min = S64_MIN >> (RTC_SEC_SHIFT + (64 - RTC_BITS)); + rtc->rtc_dev->range_max = S64_MAX >> (RTC_SEC_SHIFT + (64 - RTC_BITS)); + + platform_set_drvdata(pdev, rtc); + + return devm_rtc_register_device(rtc->rtc_dev); +} + +static const struct of_device_id macsmc_rtc_of_table[] = { + { .compatible = "apple,smc-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, macsmc_rtc_of_table); + +static struct platform_driver macsmc_rtc_driver = { + .driver = { + .name = "macsmc-rtc", + .of_match_table = macsmc_rtc_of_table, + }, + .probe = macsmc_rtc_probe, +}; +module_platform_driver(macsmc_rtc_driver); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("Apple SMC RTC driver"); +MODULE_AUTHOR("Hector Martin <marcan@marcan.st>"); diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c index dfb5bad3a369..23b7bf16b4cd 100644 --- a/drivers/rtc/rtc-max31335.c +++ b/drivers/rtc/rtc-max31335.c @@ -391,10 +391,8 @@ static int max31335_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret) return ret; - ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg, - MAX31335_STATUS1_A1F, 0); - - return 0; + return regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg, + MAX31335_STATUS1_A1F, 0); } static int max31335_alarm_irq_enable(struct device *dev, unsigned int enabled) diff --git a/drivers/rtc/rtc-nvidia-vrs10.c b/drivers/rtc/rtc-nvidia-vrs10.c new file mode 100644 index 000000000000..b15796698558 --- /dev/null +++ b/drivers/rtc/rtc-nvidia-vrs10.c @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NVIDIA Voltage Regulator Specification RTC + * + * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + */ + +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/rtc.h> + +#define NVVRS_REG_VENDOR_ID 0x00 +#define NVVRS_REG_MODEL_REV 0x01 + +/* Interrupts registers */ +#define NVVRS_REG_INT_SRC1 0x10 +#define NVVRS_REG_INT_SRC2 0x11 +#define NVVRS_REG_INT_VENDOR 0x12 + +/* Control Registers */ +#define NVVRS_REG_CTL_1 0x28 +#define NVVRS_REG_CTL_2 0x29 + +/* RTC Registers */ +#define NVVRS_REG_RTC_T3 0x70 +#define NVVRS_REG_RTC_T2 0x71 +#define NVVRS_REG_RTC_T1 0x72 +#define NVVRS_REG_RTC_T0 0x73 +#define NVVRS_REG_RTC_A3 0x74 +#define NVVRS_REG_RTC_A2 0x75 +#define NVVRS_REG_RTC_A1 0x76 +#define NVVRS_REG_RTC_A0 0x77 + +/* Interrupt Mask */ +#define NVVRS_INT_SRC1_RSTIRQ_MASK BIT(0) +#define NVVRS_INT_SRC1_OSC_MASK BIT(1) +#define NVVRS_INT_SRC1_EN_MASK BIT(2) +#define NVVRS_INT_SRC1_RTC_MASK BIT(3) +#define NVVRS_INT_SRC1_PEC_MASK BIT(4) +#define NVVRS_INT_SRC1_WDT_MASK BIT(5) +#define NVVRS_INT_SRC1_EM_PD_MASK BIT(6) +#define NVVRS_INT_SRC1_INTERNAL_MASK BIT(7) +#define NVVRS_INT_SRC2_PBSP_MASK BIT(0) +#define NVVRS_INT_SRC2_ECC_DED_MASK BIT(1) +#define NVVRS_INT_SRC2_TSD_MASK BIT(2) +#define NVVRS_INT_SRC2_LDO_MASK BIT(3) +#define NVVRS_INT_SRC2_BIST_MASK BIT(4) +#define NVVRS_INT_SRC2_RT_CRC_MASK BIT(5) +#define NVVRS_INT_SRC2_VENDOR_MASK BIT(7) +#define NVVRS_INT_VENDOR0_MASK BIT(0) +#define NVVRS_INT_VENDOR1_MASK BIT(1) +#define NVVRS_INT_VENDOR2_MASK BIT(2) +#define NVVRS_INT_VENDOR3_MASK BIT(3) +#define NVVRS_INT_VENDOR4_MASK BIT(4) +#define NVVRS_INT_VENDOR5_MASK BIT(5) +#define NVVRS_INT_VENDOR6_MASK BIT(6) +#define NVVRS_INT_VENDOR7_MASK BIT(7) + +/* Controller Register Mask */ +#define NVVRS_REG_CTL_1_FORCE_SHDN (BIT(0) | BIT(1)) +#define NVVRS_REG_CTL_1_FORCE_ACT BIT(2) +#define NVVRS_REG_CTL_1_FORCE_INT BIT(3) +#define NVVRS_REG_CTL_2_EN_PEC BIT(0) +#define NVVRS_REG_CTL_2_REQ_PEC BIT(1) +#define NVVRS_REG_CTL_2_RTC_PU BIT(2) +#define NVVRS_REG_CTL_2_RTC_WAKE BIT(3) +#define NVVRS_REG_CTL_2_RST_DLY 0xF0 + +#define ALARM_RESET_VAL 0xffffffff +#define NVVRS_MIN_MODEL_REV 0x40 + +enum nvvrs_irq_regs { + NVVRS_IRQ_REG_INT_SRC1 = 0, + NVVRS_IRQ_REG_INT_SRC2 = 1, + NVVRS_IRQ_REG_INT_VENDOR = 2, + NVVRS_IRQ_REG_COUNT = 3, +}; + +struct nvvrs_rtc_info { + struct device *dev; + struct i2c_client *client; + struct rtc_device *rtc; + unsigned int irq; +}; + +static int nvvrs_update_bits(struct nvvrs_rtc_info *info, u8 reg, + u8 mask, u8 value) +{ + int ret; + u8 val; + + ret = i2c_smbus_read_byte_data(info->client, reg); + if (ret < 0) + return ret; + + val = (u8)ret; + val &= ~mask; + val |= (value & mask); + + return i2c_smbus_write_byte_data(info->client, reg, val); +} + +static int nvvrs_rtc_write_alarm(struct i2c_client *client, u8 *time) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A3, time[3]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A2, time[2]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A1, time[1]); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A0, time[0]); +} + +static int nvvrs_rtc_enable_alarm(struct nvvrs_rtc_info *info) +{ + int ret; + + /* Set RTC_WAKE bit for autonomous wake from sleep */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE, + NVVRS_REG_CTL_2_RTC_WAKE); + if (ret < 0) + return ret; + + /* Set RTC_PU bit for autonomous wake from shutdown */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU, + NVVRS_REG_CTL_2_RTC_PU); + if (ret < 0) + return ret; + + return 0; +} + +static int nvvrs_rtc_disable_alarm(struct nvvrs_rtc_info *info) +{ + struct i2c_client *client = info->client; + u8 val[4]; + int ret; + + /* Clear RTC_WAKE bit */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE, + 0); + if (ret < 0) + return ret; + + /* Clear RTC_PU bit */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU, + 0); + if (ret < 0) + return ret; + + /* Write ALARM_RESET_VAL in RTC Alarm register to disable alarm */ + val[0] = 0xff; + val[1] = 0xff; + val[2] = 0xff; + val[3] = 0xff; + + ret = nvvrs_rtc_write_alarm(client, val); + if (ret < 0) + return ret; + + return 0; +} + +static int nvvrs_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t secs = 0; + int ret; + u8 val; + + /* + * Multi-byte transfers are not supported with PEC enabled + * Read MSB first to avoid coherency issues + */ + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T3); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= (time64_t)val << 24; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T2); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= (time64_t)val << 16; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T1); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= (time64_t)val << 8; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T0); + if (ret < 0) + return ret; + + val = (u8)ret; + secs |= val; + + rtc_time64_to_tm(secs, tm); + + return 0; +} + +static int nvvrs_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t secs; + u8 time[4]; + int ret; + + secs = rtc_tm_to_time64(tm); + time[0] = secs & 0xff; + time[1] = (secs >> 8) & 0xff; + time[2] = (secs >> 16) & 0xff; + time[3] = (secs >> 24) & 0xff; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T3, time[3]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T2, time[2]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T1, time[1]); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T0, time[0]); + + return ret; +} + +static int nvvrs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t alarm_val = 0; + int ret; + u8 val; + + /* Multi-byte transfers are not supported with PEC enabled */ + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A3); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= (time64_t)val << 24; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A2); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= (time64_t)val << 16; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A1); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= (time64_t)val << 8; + + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A0); + if (ret < 0) + return ret; + + val = (u8)ret; + alarm_val |= val; + + if (alarm_val == ALARM_RESET_VAL) + alrm->enabled = 0; + else + alrm->enabled = 1; + + rtc_time64_to_tm(alarm_val, &alrm->time); + + return 0; +} + +static int nvvrs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + time64_t secs; + u8 time[4]; + int ret; + + if (!alrm->enabled) { + ret = nvvrs_rtc_disable_alarm(info); + if (ret < 0) + return ret; + } + + ret = nvvrs_rtc_enable_alarm(info); + if (ret < 0) + return ret; + + secs = rtc_tm_to_time64(&alrm->time); + time[0] = secs & 0xff; + time[1] = (secs >> 8) & 0xff; + time[2] = (secs >> 16) & 0xff; + time[3] = (secs >> 24) & 0xff; + + ret = nvvrs_rtc_write_alarm(info->client, time); + + return ret; +} + +static int nvvrs_pseq_irq_clear(struct nvvrs_rtc_info *info) +{ + unsigned int i; + int ret; + + for (i = 0; i < NVVRS_IRQ_REG_COUNT; i++) { + ret = i2c_smbus_read_byte_data(info->client, + NVVRS_REG_INT_SRC1 + i); + if (ret < 0) { + dev_err(info->dev, "Failed to read INT_SRC%d : %d\n", + i + 1, ret); + return ret; + } + + ret = i2c_smbus_write_byte_data(info->client, + NVVRS_REG_INT_SRC1 + i, + (u8)ret); + if (ret < 0) { + dev_err(info->dev, "Failed to clear INT_SRC%d : %d\n", + i + 1, ret); + return ret; + } + } + + return 0; +} + +static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data) +{ + struct nvvrs_rtc_info *info = data; + int ret; + + /* Check for RTC alarm interrupt */ + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_INT_SRC1); + if (ret < 0) + return IRQ_NONE; + + if (ret & NVVRS_INT_SRC1_RTC_MASK) { + rtc_lock(info->rtc); + rtc_update_irq(info->rtc, 1, RTC_IRQF | RTC_AF); + rtc_unlock(info->rtc); + } + + /* Clear all interrupts */ + if (nvvrs_pseq_irq_clear(info) < 0) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int nvvrs_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + /* + * This hardware does not support enabling/disabling the alarm IRQ + * independently. The alarm is disabled by clearing the alarm time + * via set_alarm(). + */ + return 0; +} + +static const struct rtc_class_ops nvvrs_rtc_ops = { + .read_time = nvvrs_rtc_read_time, + .set_time = nvvrs_rtc_set_time, + .read_alarm = nvvrs_rtc_read_alarm, + .set_alarm = nvvrs_rtc_set_alarm, + .alarm_irq_enable = nvvrs_rtc_alarm_irq_enable, +}; + +static int nvvrs_pseq_vendor_info(struct nvvrs_rtc_info *info) +{ + struct i2c_client *client = info->client; + u8 vendor_id, model_rev; + int ret; + + ret = i2c_smbus_read_byte_data(client, NVVRS_REG_VENDOR_ID); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read Vendor ID\n"); + + vendor_id = (u8)ret; + + ret = i2c_smbus_read_byte_data(client, NVVRS_REG_MODEL_REV); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read Model Revision\n"); + + model_rev = (u8)ret; + + if (model_rev < NVVRS_MIN_MODEL_REV) { + return dev_err_probe(&client->dev, -ENODEV, + "Chip revision 0x%02x is not supported!\n", + model_rev); + } + + dev_dbg(&client->dev, "NVVRS Vendor ID: 0x%02x, Model Rev: 0x%02x\n", + vendor_id, model_rev); + + return 0; +} + +static int nvvrs_rtc_probe(struct i2c_client *client) +{ + struct nvvrs_rtc_info *info; + int ret; + + info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + if (client->irq <= 0) + return dev_err_probe(&client->dev, -EINVAL, "No IRQ specified\n"); + + info->irq = client->irq; + info->dev = &client->dev; + client->flags |= I2C_CLIENT_PEC; + i2c_set_clientdata(client, info); + info->client = client; + + /* Check vendor info */ + if (nvvrs_pseq_vendor_info(info) < 0) + return dev_err_probe(&client->dev, -EINVAL, + "Failed to get vendor info\n"); + + /* Clear any pending IRQs before requesting IRQ handler */ + if (nvvrs_pseq_irq_clear(info) < 0) + return dev_err_probe(&client->dev, -EINVAL, + "Failed to clear interrupts\n"); + + /* Allocate RTC device */ + info->rtc = devm_rtc_allocate_device(info->dev); + if (IS_ERR(info->rtc)) + return PTR_ERR(info->rtc); + + info->rtc->ops = &nvvrs_rtc_ops; + info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc->range_max = RTC_TIMESTAMP_END_2099; + + /* Request RTC IRQ */ + ret = devm_request_threaded_irq(info->dev, info->irq, NULL, + nvvrs_rtc_irq_handler, IRQF_ONESHOT, + "nvvrs-rtc", info); + if (ret < 0) { + dev_err_probe(info->dev, ret, "Failed to request RTC IRQ\n"); + return ret; + } + + /* RTC as a wakeup source */ + devm_device_init_wakeup(info->dev); + + return devm_rtc_register_device(info->rtc); +} + +#ifdef CONFIG_PM_SLEEP +static int nvvrs_rtc_suspend(struct device *dev) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + int ret; + + if (device_may_wakeup(dev)) { + /* Set RTC_WAKE bit for auto wake system from suspend state */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, + NVVRS_REG_CTL_2_RTC_WAKE, + NVVRS_REG_CTL_2_RTC_WAKE); + if (ret < 0) { + dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n", + ret); + return ret; + } + + return enable_irq_wake(info->irq); + } + + return 0; +} + +static int nvvrs_rtc_resume(struct device *dev) +{ + struct nvvrs_rtc_info *info = dev_get_drvdata(dev); + int ret; + + if (device_may_wakeup(dev)) { + /* Clear FORCE_ACT bit */ + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_1, + NVVRS_REG_CTL_1_FORCE_ACT, 0); + if (ret < 0) { + dev_err(info->dev, "Failed to clear FORCE_ACT bit (%d)\n", + ret); + return ret; + } + + return disable_irq_wake(info->irq); + } + + return 0; +} + +#endif +static SIMPLE_DEV_PM_OPS(nvvrs_rtc_pm_ops, nvvrs_rtc_suspend, nvvrs_rtc_resume); + +static const struct of_device_id nvvrs_rtc_of_match[] = { + { .compatible = "nvidia,vrs-10" }, + { }, +}; +MODULE_DEVICE_TABLE(of, nvvrs_rtc_of_match); + +static struct i2c_driver nvvrs_rtc_driver = { + .driver = { + .name = "rtc-nvidia-vrs10", + .pm = &nvvrs_rtc_pm_ops, + .of_match_table = nvvrs_rtc_of_match, + }, + .probe = nvvrs_rtc_probe, +}; + +module_i2c_driver(nvvrs_rtc_driver); + +MODULE_AUTHOR("Shubhi Garg <shgarg@nvidia.com>"); +MODULE_DESCRIPTION("NVIDIA Voltage Regulator Specification RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c index 2812da2c50c5..52c11532bc3a 100644 --- a/drivers/rtc/rtc-pic32.c +++ b/drivers/rtc/rtc-pic32.c @@ -340,8 +340,6 @@ static int pic32_rtc_probe(struct platform_device *pdev) if (ret) goto err_nortc; - pdata->rtc->max_user_freq = 128; - pic32_rtc_setfreq(&pdev->dev, 1); ret = devm_request_irq(&pdev->dev, pdata->alarm_irq, pic32_rtc_alarmirq, 0, diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c index ab816bdf0d77..cbabaa4dc96a 100644 --- a/drivers/rtc/rtc-renesas-rtca3.c +++ b/drivers/rtc/rtc-renesas-rtca3.c @@ -726,7 +726,7 @@ static int rtca3_probe(struct platform_device *pdev) if (ret) return ret; - priv->rstc = devm_reset_control_get_shared(dev, NULL); + priv->rstc = devm_reset_control_array_get_shared(dev); if (IS_ERR(priv->rstc)) return PTR_ERR(priv->rstc); @@ -772,7 +772,6 @@ static int rtca3_probe(struct platform_device *pdev) return PTR_ERR(priv->rtc_dev); priv->rtc_dev->ops = &rtca3_ops; - priv->rtc_dev->max_user_freq = 256; priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index c2a531f0e125..d96f6bb68850 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -1023,8 +1023,6 @@ static int rv3028_probe(struct i2c_client *client) eeprom_cfg.priv = rv3028; devm_rtc_nvmem_register(rv3028->rtc, &eeprom_cfg); - rv3028->rtc->max_user_freq = 1; - #ifdef CONFIG_COMMON_CLK rv3028_clkout_register_clk(rv3028, client); #endif diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index b8376bd1d905..6c09da7738e1 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -968,8 +968,6 @@ static int rv3032_probe(struct i2c_client *client) eeprom_cfg.priv = rv3032; devm_rtc_nvmem_register(rv3032->rtc, &eeprom_cfg); - rv3032->rtc->max_user_freq = 1; - #ifdef CONFIG_COMMON_CLK rv3032_clkout_register_clk(rv3032, client); #endif diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 1327251e527c..4e9e04cbec89 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -738,8 +738,6 @@ static int rv8803_probe(struct i2c_client *client) devm_rtc_nvmem_register(rv8803->rtc, &nvmem_cfg); - rv8803->rtc->max_user_freq = 1; - return 0; } diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 7c423d672adb..07bf35ac8d79 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -324,8 +324,6 @@ static int rx6110_probe(struct rx6110_data *rx6110, struct device *dev) if (err) return err; - rx6110->rtc->max_user_freq = 1; - return 0; } diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 2b6198d1cf81..171240e50f48 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -412,7 +412,6 @@ static int rx8010_probe(struct i2c_client *client) } rx8010->rtc->ops = &rx8010_rtc_ops; - rx8010->rtc->max_user_freq = 1; rx8010->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rx8010->rtc->range_max = RTC_TIMESTAMP_END_2099; diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 7e9f7cb90c28..ced6e7adfe8d 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -565,8 +565,6 @@ static int rx8025_probe(struct i2c_client *client) clear_bit(RTC_FEATURE_ALARM, rx8025->rtc->features); } - rx8025->rtc->max_user_freq = 1; - set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rx8025->rtc->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rx8025->rtc->features); diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index 3408d2ab2741..07bd983b5692 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -66,7 +66,7 @@ struct s35390a { int twentyfourhour; }; -static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) +static int s35390a_set_reg(struct s35390a *s35390a, int reg, u8 *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { @@ -83,7 +83,7 @@ static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) return 0; } -static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) +static int s35390a_get_reg(struct s35390a *s35390a, int reg, u8 *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { @@ -168,7 +168,7 @@ static int s35390a_read_status(struct s35390a *s35390a, char *status1) static int s35390a_disable_test_mode(struct s35390a *s35390a) { - char buf[1]; + u8 buf[1]; if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0) return -EIO; @@ -210,7 +210,7 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm) struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); int i; - char buf[7], status; + u8 buf[7], status; dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, " "mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, @@ -239,7 +239,7 @@ static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char buf[7], status; + u8 buf[7], status; int i, err; if (s35390a_read_status(s35390a, &status) == 1) @@ -273,7 +273,7 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char buf[3], sts = 0; + u8 buf[3], sts = 0; int err, i; dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\ @@ -326,7 +326,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char buf[3], sts; + u8 buf[3], sts; int i, err; err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); @@ -383,7 +383,7 @@ static int s35390a_rtc_ioctl(struct device *dev, unsigned int cmd, { struct i2c_client *client = to_i2c_client(dev); struct s35390a *s35390a = i2c_get_clientdata(client); - char sts; + u8 sts; int err; switch (cmd) { @@ -422,7 +422,7 @@ static int s35390a_probe(struct i2c_client *client) unsigned int i; struct s35390a *s35390a; struct rtc_device *rtc; - char buf, status1; + u8 buf, status1; struct device *dev = &client->dev; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 1ad93648d69c..26b2f4184ecc 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -40,8 +40,6 @@ #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 -#define RTC_FREQ 1024 - static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { @@ -202,7 +200,6 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) } info->rtc->ops = &sa1100_rtc_ops; - info->rtc->max_user_freq = RTC_FREQ; info->rtc->range_max = U32_MAX; ret = devm_rtc_register_device(info->rtc); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 619800a00479..0510dc64c3e2 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -423,7 +423,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) writeb(tmp, rtc->regbase + RCR1); rtc->rtc_dev->ops = &sh_rtc_ops; - rtc->rtc_dev->max_user_freq = 256; if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900; diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 46788db89953..528e32b7d101 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -274,6 +274,12 @@ static const struct of_device_id tegra_rtc_dt_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match); +static const struct acpi_device_id tegra_rtc_acpi_match[] = { + { "NVDA0280" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, tegra_rtc_acpi_match); + static int tegra_rtc_probe(struct platform_device *pdev) { struct tegra_rtc_info *info; @@ -300,13 +306,11 @@ static int tegra_rtc_probe(struct platform_device *pdev) info->rtc->ops = &tegra_rtc_ops; info->rtc->range_max = U32_MAX; - info->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(info->clk)) - return PTR_ERR(info->clk); - - ret = clk_prepare_enable(info->clk); - if (ret < 0) - return ret; + if (dev_of_node(&pdev->dev)) { + info->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(info->clk)) + return PTR_ERR(info->clk); + } /* set context info */ info->pdev = pdev; @@ -324,32 +328,18 @@ static int tegra_rtc_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler, IRQF_TRIGGER_HIGH, dev_name(&pdev->dev), &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret); - goto disable_clk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to request interrupt\n"); ret = devm_rtc_register_device(info->rtc); if (ret) - goto disable_clk; + return ret; dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); return 0; - -disable_clk: - clk_disable_unprepare(info->clk); - return ret; -} - -static void tegra_rtc_remove(struct platform_device *pdev) -{ - struct tegra_rtc_info *info = platform_get_drvdata(pdev); - - clk_disable_unprepare(info->clk); } -#ifdef CONFIG_PM_SLEEP static int tegra_rtc_suspend(struct device *dev) { struct tegra_rtc_info *info = dev_get_drvdata(dev); @@ -387,9 +377,8 @@ static int tegra_rtc_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume); static void tegra_rtc_shutdown(struct platform_device *pdev) { @@ -399,12 +388,12 @@ static void tegra_rtc_shutdown(struct platform_device *pdev) static struct platform_driver tegra_rtc_driver = { .probe = tegra_rtc_probe, - .remove = tegra_rtc_remove, .shutdown = tegra_rtc_shutdown, .driver = { .name = "tegra_rtc", .of_match_table = tegra_rtc_dt_match, - .pm = &tegra_rtc_pm_ops, + .acpi_match_table = tegra_rtc_acpi_match, + .pm = pm_sleep_ptr(&tegra_rtc_pm_ops), }, }; module_platform_driver(tegra_rtc_driver); diff --git a/drivers/s390/char/sclp_mem.c b/drivers/s390/char/sclp_mem.c index 676c085b4f8a..27f0d2f12a8b 100644 --- a/drivers/s390/char/sclp_mem.c +++ b/drivers/s390/char/sclp_mem.c @@ -44,6 +44,9 @@ struct sclp_mem { unsigned int id; unsigned int memmap_on_memory; unsigned int config; +#ifdef CONFIG_KASAN + unsigned int early_shadow_mapped; +#endif }; struct sclp_mem_arg { @@ -244,6 +247,16 @@ static ssize_t sclp_config_mem_store(struct kobject *kobj, struct kobj_attribute put_device(&mem->dev); sclp_mem_change_state(addr, block_size, 0); __remove_memory(addr, block_size); +#ifdef CONFIG_KASAN + if (sclp_mem->early_shadow_mapped) { + unsigned long start, end; + + start = (unsigned long)kasan_mem_to_shadow(__va(addr)); + end = start + (block_size >> KASAN_SHADOW_SCALE_SHIFT); + vmemmap_free(start, end, NULL); + sclp_mem->early_shadow_mapped = 0; + } +#endif WRITE_ONCE(sclp_mem->config, 0); } out_unlock: @@ -316,6 +329,9 @@ static int sclp_create_mem(struct sclp_mem *sclp_mem, struct kset *kset, sclp_mem->memmap_on_memory = memmap_on_memory; sclp_mem->config = config; +#ifdef CONFIG_KASAN + sclp_mem->early_shadow_mapped = config; +#endif sclp_mem->id = id; kobject_init(&sclp_mem->kobj, &ktype); rc = kobject_add(&sclp_mem->kobj, &kset->kobj, "memory%d", id); diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index e3e0e9f36527..a226ff208eda 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -154,7 +154,7 @@ static struct urdev *urdev_get_from_devno(u16 devno) struct ccw_device *cdev; struct urdev *urd; - sprintf(bus_id, "0.0.%04x", devno); + scnprintf(bus_id, sizeof(bus_id), "0.0.%04x", devno); cdev = get_ccwdev_by_busid(&ur_driver, bus_id); if (!cdev) return NULL; @@ -904,11 +904,11 @@ static int ur_set_online(struct ccw_device *cdev) goto fail_free_cdev; if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) { if (urd->class == DEV_CLASS_UR_I) - sprintf(node_id, "vmrdr-%s", dev_name(&cdev->dev)); + scnprintf(node_id, sizeof(node_id), "vmrdr-%s", dev_name(&cdev->dev)); if (urd->class == DEV_CLASS_UR_O) - sprintf(node_id, "vmpun-%s", dev_name(&cdev->dev)); + scnprintf(node_id, sizeof(node_id), "vmpun-%s", dev_name(&cdev->dev)); } else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) { - sprintf(node_id, "vmprt-%s", dev_name(&cdev->dev)); + scnprintf(node_id, sizeof(node_id), "vmprt-%s", dev_name(&cdev->dev)); } else { rc = -EOPNOTSUPP; goto fail_free_cdev; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 5c602c057798..45b0e33293a5 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1260,6 +1260,7 @@ static void imm_detach(struct parport *pb) imm_struct *dev; list_for_each_entry(dev, &imm_hosts, list) { if (dev->dev->port == pb) { + disable_delayed_work_sync(&dev->imm_tq); list_del_init(&dev->list); scsi_remove_host(dev->host); scsi_host_put(dev->host); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 95123689e9d1..dbd58a7e7bc1 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -61,8 +61,8 @@ #include <linux/hdreg.h> #include <linux/reboot.h> #include <linux/stringify.h> +#include <linux/irq.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/processor.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -7844,6 +7844,30 @@ static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd) } /** + * ipr_set_affinity_nobalance + * @ioa_cfg: ipr_ioa_cfg struct for an ipr device + * @flag: bool + * true: ensable "IRQ_NO_BALANCING" bit for msix interrupt + * false: disable "IRQ_NO_BALANCING" bit for msix interrupt + * Description: This function will be called to disable/enable + * "IRQ_NO_BALANCING" to avoid irqbalance daemon + * kicking in during adapter reset. + **/ +static void ipr_set_affinity_nobalance(struct ipr_ioa_cfg *ioa_cfg, bool flag) +{ + int irq, i; + + for (i = 0; i < ioa_cfg->nvectors; i++) { + irq = pci_irq_vector(ioa_cfg->pdev, i); + + if (flag) + irq_set_status_flags(irq, IRQ_NO_BALANCING); + else + irq_clear_status_flags(irq, IRQ_NO_BALANCING); + } +} + +/** * ipr_reset_restore_cfg_space - Restore PCI config space. * @ipr_cmd: ipr command struct * @@ -7866,6 +7890,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_CONTINUE; } + ipr_set_affinity_nobalance(ioa_cfg, false); ipr_fail_all_ops(ioa_cfg); if (ioa_cfg->sis64) { @@ -7945,6 +7970,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc == PCIBIOS_SUCCESSFUL) { + ipr_set_affinity_nobalance(ioa_cfg, true); ipr_cmd->job_step = ipr_reset_bist_done; ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 8566bb1208a0..6b15ad1bcada 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -141,6 +141,7 @@ Undo_event_q: Undo_ports: sas_unregister_ports(sas_ha); Undo_phys: + sas_unregister_phys(sas_ha); return error; } diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 6706f2be8d27..d104c87f04f5 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -54,6 +54,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev); void sas_scsi_recover_host(struct Scsi_Host *shost); int sas_register_phys(struct sas_ha_struct *sas_ha); +void sas_unregister_phys(struct sas_ha_struct *sas_ha); struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags); void sas_free_event(struct asd_sas_event *event); @@ -145,20 +146,6 @@ static inline void sas_fail_probe(struct domain_device *dev, const char *func, i func, dev->parent ? "exp-attached" : "direct-attached", SAS_ADDR(dev->sas_addr), err); - - /* - * If the device probe failed, the expander phy attached address - * needs to be reset so that the phy will not be treated as flutter - * in the next revalidation - */ - if (dev->parent && !dev_is_expander(dev->dev_type)) { - struct sas_phy *phy = dev->phy; - struct domain_device *parent = dev->parent; - struct ex_phy *ex_phy = &parent->ex_dev.ex_phy[phy->number]; - - memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE); - } - sas_unregister_dev(dev->port, dev); } diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 635835c28ecd..58f08dc2c187 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -116,6 +116,7 @@ static void sas_phye_shutdown(struct work_struct *work) int sas_register_phys(struct sas_ha_struct *sas_ha) { int i; + int err; /* Now register the phys. */ for (i = 0; i < sas_ha->num_phys; i++) { @@ -132,8 +133,10 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->frame_rcvd_size = 0; phy->phy = sas_phy_alloc(&sas_ha->shost->shost_gendev, i); - if (!phy->phy) - return -ENOMEM; + if (!phy->phy) { + err = -ENOMEM; + goto rollback; + } phy->phy->identify.initiator_port_protocols = phy->iproto; @@ -146,10 +149,34 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; - sas_phy_add(phy->phy); + err = sas_phy_add(phy->phy); + if (err) { + sas_phy_free(phy->phy); + goto rollback; + } } return 0; +rollback: + for (i-- ; i >= 0 ; i--) { + struct asd_sas_phy *phy = sas_ha->sas_phy[i]; + + sas_phy_delete(phy->phy); + sas_phy_free(phy->phy); + } + return err; +} + +void sas_unregister_phys(struct sas_ha_struct *sas_ha) +{ + int i; + + for (i = 0 ; i < sas_ha->num_phys ; i++) { + struct asd_sas_phy *phy = sas_ha->sas_phy[i]; + + sas_phy_delete(phy->phy); + sas_phy_free(phy->phy); + } } const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 6742684e2990..31d68c151b20 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -56,8 +56,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.15.0.5.50" -#define MPI3MR_DRIVER_RELDATE "12-August-2025" +#define MPI3MR_DRIVER_VERSION "8.15.0.5.51" +#define MPI3MR_DRIVER_RELDATE "18-November-2025" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index b88633e1efe2..d4ca878d0886 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1184,6 +1184,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, if (is_added == true) tgtdev->io_throttle_enabled = (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0; + if (!mrioc->sas_transport_enabled) + tgtdev->non_stl = 1; switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) { case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB: @@ -4844,7 +4846,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget) spin_lock_irqsave(&mrioc->tgtdev_lock, flags); if (starget->channel == mrioc->scsi_device_channel) { tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); - if (tgt_dev && !tgt_dev->is_hidden) { + if (tgt_dev && !tgt_dev->is_hidden && tgt_dev->non_stl) { scsi_tgt_priv_data->starget = starget; scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3a57f07d73f5..16a44c0917e1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -17,6 +17,7 @@ #include <linux/crash_dump.h> #include <linux/trace_events.h> #include <linux/trace.h> +#include <linux/irq.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> @@ -7776,6 +7777,31 @@ static void qla_pci_error_cleanup(scsi_qla_host_t *vha) } +/** + * qla2xxx_set_affinity_nobalance + * @pdev: pci_dev struct for a qla2xxx device + * @flag: bool + * true: enable "IRQ_NO_BALANCING" bit for msix interrupt + * false: disable "IRQ_NO_BALANCING" bit for msix interrupt + * Description: This function will be called to disable/enable + * "IRQ_NO_BALANCING" to avoid irqbalance daemon + * kicking in during adapter reset. + **/ + +static void qla2xxx_set_affinity_nobalance(struct pci_dev *pdev, bool flag) +{ + int irq, i; + + for (i = 0; i < QLA_BASE_VECTORS; i++) { + irq = pci_irq_vector(pdev, i); + + if (flag) + irq_set_status_flags(irq, IRQ_NO_BALANCING); + else + irq_clear_status_flags(irq, IRQ_NO_BALANCING); + } +} + static pci_ers_result_t qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { @@ -7794,6 +7820,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) goto out; } + qla2xxx_set_affinity_nobalance(pdev, false); + switch (state) { case pci_channel_io_normal: qla_pci_set_eeh_busy(vha); @@ -7930,6 +7958,8 @@ exit_slot_reset: ql_dbg(ql_dbg_aer, base_vha, 0x900e, "Slot Reset returning %x.\n", ret); + qla2xxx_set_affinity_nobalance(pdev, true); + return ret; } diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index da2fc66ffedd..b0a62aaa1cca 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1552,7 +1552,7 @@ static int qla4_82xx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val) (val == PHAN_INITIALIZE_ACK)) return 0; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(500); + schedule_timeout(msecs_to_jiffies(500)); } while (--retries); diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 7b56e00c7df6..b9d805317814 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -353,7 +353,8 @@ EXPORT_SYMBOL_GPL(scsi_dh_attach); * that may have a device handler attached * @gfp - the GFP mask used in the kmalloc() call when allocating memory * - * Returns name of attached handler, NULL if no handler is attached. + * Returns name of attached handler, NULL if no handler is attached, or + * and error pointer if an error occurred. * Caller must take care to free the returned string. */ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) @@ -363,10 +364,11 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) sdev = scsi_device_from_queue(q); if (!sdev) - return NULL; + return ERR_PTR(-ENODEV); if (sdev->handler) - handler_name = kstrdup(sdev->handler->name, gfp); + handler_name = kstrdup(sdev->handler->name, gfp) ? : + ERR_PTR(-ENOMEM); put_device(&sdev->sdev_gendev); return handler_name; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 51ad2ad07e43..93031326ac3e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2801,7 +2801,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple); * * Must be called with user context, may sleep. * - * Returns zero if unsuccessful or an error if not. + * Returns zero if successful or an error if not. */ int scsi_device_quiesce(struct scsi_device *sdev) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f2c0744b4480..f50b92e63201 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2004,9 +2004,19 @@ static int sd_pr_read_keys(struct block_device *bdev, struct pr_keys *keys_info) { int result, i, data_offset, num_copy_keys; u32 num_keys = keys_info->num_keys; - int data_len = num_keys * 8 + 8; + int data_len; u8 *data; + /* + * Each reservation key takes 8 bytes and there is an 8-byte header + * before the reservation key list. The total size must fit into the + * 16-bit ALLOCATION LENGTH field. + */ + if (check_mul_overflow(num_keys, 8, &data_len) || + check_add_overflow(data_len, 8, &data_len) || + data_len > USHRT_MAX) + return -EINVAL; + data = kzalloc(data_len, GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 55c1db816534..fb68738dfb9b 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -2052,8 +2052,14 @@ EXPORT_SYMBOL(sdw_clear_slave_status); int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { - if (msg->len > SDW_BPT_MSG_MAX_BYTES) { - dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len); + int len = 0; + int i; + + for (i = 0; i < msg->sections; i++) + len += msg->sec[i].len; + + if (len > SDW_BPT_MSG_MAX_BYTES) { + dev_err(bus->dev, "Invalid BPT message length %d\n", len); return -EINVAL; } diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 02651fbb683a..8115c64dd48e 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -73,21 +73,31 @@ struct sdw_msg { }; /** - * struct sdw_btp_msg - Message structure + * struct sdw_btp_section - Message section structure * @addr: Start Register address accessed in the Slave * @len: number of bytes to transfer. More than 64Kb can be transferred * but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced. - * @dev_num: Slave device number - * @flags: transfer flags, indicate if xfer is read or write - * @buf: message data buffer (filled by host for write, filled + * @buf: section data buffer (filled by host for write, filled * by Peripheral hardware for reads) */ -struct sdw_bpt_msg { +struct sdw_bpt_section { u32 addr; u32 len; + u8 *buf; +}; + +/** + * struct sdw_btp_msg - Message structure + * @sec: Pointer to array of sections + * @sections: Number of sections in the array + * @dev_num: Slave device number + * @flags: transfer flags, indicate if xfer is read or write + */ +struct sdw_bpt_msg { + struct sdw_bpt_section *sec; + int sections; u8 dev_num; u8 flags; - u8 *buf; }; #define SDW_DOUBLE_RATE_FACTOR 2 diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 21bb491d026b..a106e5e482c8 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -2094,6 +2094,36 @@ static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size return total * 2; } +int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */ + int row, int col, int frame_rate, + unsigned int *tx_dma_bandwidth, + unsigned int *rx_dma_bandwidth) +{ + unsigned int bpt_bits = row * (col - 1); + unsigned int bpt_bytes = bpt_bits >> 3; + unsigned int pdi0_buffer_size; + unsigned int pdi1_buffer_size; + unsigned int data_per_frame; + + data_per_frame = sdw_cdns_bra_actual_data_size(bpt_bytes); + if (!data_per_frame) + return -EINVAL; + + if (command == 0) { + pdi0_buffer_size = sdw_cdns_write_pdi0_buffer_size(data_per_frame); + pdi1_buffer_size = SDW_CDNS_WRITE_PDI1_BUFFER_SIZE; + } else { + pdi0_buffer_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE; + pdi1_buffer_size = sdw_cdns_read_pdi1_buffer_size(data_per_frame); + } + + *tx_dma_bandwidth = pdi0_buffer_size * 8 * frame_rate; + *rx_dma_bandwidth = pdi1_buffer_size * 8 * frame_rate; + + return 0; +} +EXPORT_SYMBOL(sdw_cdns_bpt_find_bandwidth); + int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ int row, int col, unsigned int data_bytes, unsigned int requested_bytes_per_frame, @@ -2114,9 +2144,6 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ if (!actual_bpt_bytes) return -EINVAL; - if (data_bytes < actual_bpt_bytes) - actual_bpt_bytes = data_bytes; - /* * the caller may want to set the number of bytes per frame, * allow when possible @@ -2126,6 +2153,9 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ *data_per_frame = actual_bpt_bytes; + if (data_bytes < actual_bpt_bytes) + actual_bpt_bytes = data_bytes; + if (command == 0) { /* * for writes we need to send all the data_bytes per frame, @@ -2294,17 +2324,20 @@ static int sdw_cdns_prepare_read_pd0_buffer(u8 *header, unsigned int header_size #define CDNS_BPT_ROLLING_COUNTER_START 1 -int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, - int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes) +int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, + int data_per_frame, u8 *dma_buffer, + int dma_buffer_size, int *dma_buffer_total_bytes) { int total_dma_data_written = 0; u8 *p_dma_buffer = dma_buffer; u8 header[SDW_CDNS_BRA_HDR]; + unsigned int start_register; + unsigned int section_size; int dma_data_written; - u8 *p_data = data; + u8 *p_data; u8 counter; int ret; + int i; counter = CDNS_BPT_ROLLING_COUNTER_START; @@ -2312,47 +2345,57 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, header[0] |= GENMASK(7, 6); /* header is active */ header[0] |= (dev_num << 2); - while (data_size >= data_per_frame) { - header[1] = data_per_frame; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; - - ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, - p_data, data_per_frame, - p_dma_buffer, dma_buffer_size, - &dma_data_written, counter); - if (ret < 0) - return ret; + for (i = 0; i < num_sec; i++) { + start_register = sec[i].addr; + section_size = sec[i].len; + p_data = sec[i].buf; - counter++; + while (section_size >= data_per_frame) { + header[1] = data_per_frame; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; - p_data += data_per_frame; - data_size -= data_per_frame; + ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_data, data_per_frame, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; - p_dma_buffer += dma_data_written; - dma_buffer_size -= dma_data_written; - total_dma_data_written += dma_data_written; + counter++; - start_register += data_per_frame; - } + p_data += data_per_frame; + section_size -= data_per_frame; - if (data_size) { - header[1] = data_size; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; - ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, - p_data, data_size, - p_dma_buffer, dma_buffer_size, - &dma_data_written, counter); - if (ret < 0) - return ret; + start_register += data_per_frame; + } - total_dma_data_written += dma_data_written; + if (section_size) { + header[1] = section_size; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; + + ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_data, section_size, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; + + counter++; + + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; + } } *dma_buffer_total_bytes = total_dma_data_written; @@ -2361,16 +2404,19 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, } EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer); -int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size, +int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes) + int *dma_buffer_total_bytes, unsigned int fake_size) { int total_dma_data_written = 0; u8 *p_dma_buffer = dma_buffer; u8 header[SDW_CDNS_BRA_HDR]; + unsigned int start_register; + unsigned int data_size; int dma_data_written; u8 counter; int ret; + int i; counter = CDNS_BPT_ROLLING_COUNTER_START; @@ -2378,13 +2424,58 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si header[0] |= GENMASK(7, 6); /* header is active */ header[0] |= (dev_num << 2); - while (data_size >= data_per_frame) { - header[1] = data_per_frame; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; + for (i = 0; i < num_sec; i++) { + start_register = sec[i].addr; + data_size = sec[i].len; + while (data_size >= data_per_frame) { + header[1] = data_per_frame; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; + + ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; + + counter++; + + data_size -= data_per_frame; + + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; + + start_register += data_per_frame; + } + + if (data_size) { + header[1] = data_size; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; + + ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, + p_dma_buffer, dma_buffer_size, + &dma_data_written, counter); + if (ret < 0) + return ret; + + counter++; + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; + } + } + + /* Add fake frame */ + header[0] &= ~GENMASK(7, 6); /* Set inactive flag in BPT/BRA frame heade */ + while (fake_size >= data_per_frame) { + header[1] = data_per_frame; ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer, dma_buffer_size, &dma_data_written, counter); @@ -2393,28 +2484,24 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si counter++; - data_size -= data_per_frame; - + fake_size -= data_per_frame; p_dma_buffer += dma_data_written; dma_buffer_size -= dma_data_written; total_dma_data_written += dma_data_written; - - start_register += data_per_frame; } - if (data_size) { - header[1] = data_size; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; - + if (fake_size) { + header[1] = fake_size; ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer, dma_buffer_size, &dma_data_written, counter); if (ret < 0) return ret; + counter++; + + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; total_dma_data_written += dma_data_written; } @@ -2495,14 +2582,14 @@ int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer, ret = check_frame_start(header, counter); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d start header %x\n", - __func__, i, num_frames, header); + __func__, i + 1, num_frames, header); return ret; } ret = check_frame_end(footer); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d end footer %x\n", - __func__, i, num_frames, footer); + __func__, i + 1, num_frames, footer); return ret; } @@ -2549,9 +2636,12 @@ static u8 extract_read_data(u32 *data, int num_bytes, u8 *buffer) } int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, - u8 *buffer, int buffer_size, int num_frames, int data_per_frame) + struct sdw_bpt_section *sec, int num_sec, int num_frames, + int data_per_frame) { int total_num_bytes = 0; + int buffer_size = 0; + int sec_index; u32 *p_data; u8 *p_buf; int counter; @@ -2565,7 +2655,10 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf counter = CDNS_BPT_ROLLING_COUNTER_START; p_data = (u32 *)dma_buffer; - p_buf = buffer; + + sec_index = 0; + p_buf = sec[sec_index].buf; + buffer_size = sec[sec_index].len; for (i = 0; i < num_frames; i++) { header = *p_data++; @@ -2573,7 +2666,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf ret = check_frame_start(header, counter); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d start header %x\n", - __func__, i, num_frames, header); + __func__, i + 1, num_frames, header); return ret; } @@ -2588,7 +2681,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf if (crc != expected_crc) { dev_err(dev, "%s: bad frame %d/%d crc %#x expected %#x\n", - __func__, i, num_frames, crc, expected_crc); + __func__, i + 1, num_frames, crc, expected_crc); return -EIO; } @@ -2599,12 +2692,24 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf ret = check_frame_end(footer); if (ret < 0) { dev_err(dev, "%s: bad frame %d/%d end footer %x\n", - __func__, i, num_frames, footer); + __func__, i + 1, num_frames, footer); return ret; } counter++; counter &= GENMASK(3, 0); + + if (buffer_size == total_num_bytes && (i + 1) < num_frames) { + sec_index++; + if (sec_index >= num_sec) { + dev_err(dev, "%s: incorrect section index %d i %d\n", + __func__, sec_index, i); + return -EINVAL; + } + p_buf = sec[sec_index].buf; + buffer_size = sec[sec_index].len; + total_num_bytes = 0; + } } return 0; } diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 9373426c7f63..668f807cff4b 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ /* Copyright(c) 2015-17 Intel Corporation. */ #include <sound/soc.h> +#include "bus.h" #ifndef __SDW_CADENCE_H #define __SDW_CADENCE_H @@ -209,23 +210,29 @@ void sdw_cdns_config_update(struct sdw_cdns *cdns); int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns); /* SoundWire BPT/BRA helpers to format data */ +int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */ + int row, int col, int frame_rate, + unsigned int *tx_dma_bandwidth, + unsigned int *rx_dma_bandwidth); + int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ int row, int col, unsigned int data_bytes, unsigned int requested_bytes_per_frame, unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, unsigned int *pdi1_buffer_size, unsigned int *num_frames); -int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, - int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes); +int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, + int data_per_frame, u8 *dma_buffer, + int dma_buffer_size, int *dma_buffer_total_bytes); -int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size, +int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec, int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes); + int *dma_buffer_total_bytes, unsigned int fake_size); int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, int num_frames); int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, - u8 *buffer, int buffer_size, int num_frames, int data_per_frame); + struct sdw_bpt_section *sec, int num_sec, int num_frames, + int data_per_frame); #endif /* __SDW_CADENCE_H */ diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c index 1e0f9318b616..6068011dd0d9 100644 --- a/drivers/soundwire/debugfs.c +++ b/drivers/soundwire/debugfs.c @@ -222,15 +222,23 @@ DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL, static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer) { struct sdw_bpt_msg msg = {0}; + struct sdw_bpt_section *sec; - msg.addr = start_addr; - msg.len = num_bytes; + sec = kcalloc(1, sizeof(*sec), GFP_KERNEL); + if (!sec) + return -ENOMEM; + msg.sections = 1; + + sec[0].addr = start_addr; + sec[0].len = num_bytes; + + msg.sec = sec; msg.dev_num = slave->dev_num; if (write) msg.flags = SDW_MSG_FLAG_WRITE; else msg.flags = SDW_MSG_FLAG_READ; - msg.buf = buffer; + sec[0].buf = buffer; return sdw_bpt_send_sync(slave->bus, slave, &msg); } diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index c18f0c16f929..530ac66ac6fa 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -124,6 +124,9 @@ static void sdw_compute_dp0_port_params(struct sdw_bus *bus) struct sdw_master_runtime *m_rt; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + /* DP0 is for BPT only */ + if (m_rt->stream->type != SDW_STREAM_BPT) + continue; sdw_compute_dp0_master_ports(m_rt); sdw_compute_dp0_slave_ports(m_rt); } diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 5d08364ad6d1..1ed0251d2592 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -44,6 +44,8 @@ static int sdw_slave_bpt_stream_add(struct sdw_slave *slave, struct sdw_stream_r return ret; } +#define READ_PDI1_MIN_SIZE 12 + static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { @@ -53,19 +55,31 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * struct sdw_stream_runtime *stream; struct sdw_stream_config sconfig; struct sdw_port_config *pconfig; + unsigned int pdi0_buf_size_pre_frame; + unsigned int pdi1_buf_size_pre_frame; + unsigned int pdi0_buffer_size_; + unsigned int pdi1_buffer_size_; unsigned int pdi0_buffer_size; unsigned int tx_dma_bandwidth; unsigned int pdi1_buffer_size; unsigned int rx_dma_bandwidth; + unsigned int fake_num_frames; unsigned int data_per_frame; unsigned int tx_total_bytes; struct sdw_cdns_pdi *pdi0; struct sdw_cdns_pdi *pdi1; + unsigned int rx_alignment; + unsigned int tx_alignment; + unsigned int num_frames_; unsigned int num_frames; + unsigned int fake_size; + unsigned int tx_pad; + unsigned int rx_pad; int command; int ret1; int ret; int dir; + int len; int i; stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT); @@ -138,23 +152,77 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1; - ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, - msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame, - &pdi0_buffer_size, &pdi1_buffer_size, &num_frames); + ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row, + cdns->bus.params.col, + prop->default_frame_rate, + &tx_dma_bandwidth, &rx_dma_bandwidth); if (ret < 0) goto deprepare_stream; + len = 0; + pdi0_buffer_size = 0; + pdi1_buffer_size = 0; + num_frames = 0; + /* Add up pdi buffer size and frame numbers of each BPT sections */ + for (i = 0; i < msg->sections; i++) { + ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, + cdns->bus.params.col, + msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES, + &data_per_frame, &pdi0_buffer_size_, + &pdi1_buffer_size_, &num_frames_); + if (ret < 0) + goto deprepare_stream; + + len += msg->sec[i].len; + pdi0_buffer_size += pdi0_buffer_size_; + pdi1_buffer_size += pdi1_buffer_size_; + num_frames += num_frames_; + } + sdw->bpt_ctx.pdi0_buffer_size = pdi0_buffer_size; sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size; sdw->bpt_ctx.num_frames = num_frames; sdw->bpt_ctx.data_per_frame = data_per_frame; - tx_dma_bandwidth = div_u64((u64)pdi0_buffer_size * 8 * (u64)prop->default_frame_rate, - num_frames); - rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate, - num_frames); + + rx_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth); + tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth); + + if (command) { /* read */ + /* Get buffer size of a full frame */ + ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, + cdns->bus.params.col, + data_per_frame, SDW_BPT_MSG_MAX_BYTES, + &data_per_frame, &pdi0_buf_size_pre_frame, + &pdi1_buf_size_pre_frame, &fake_num_frames); + if (ret < 0) + goto deprepare_stream; + + /* find fake pdi1 buffer size */ + rx_pad = rx_alignment - (pdi1_buffer_size % rx_alignment); + while (rx_pad <= READ_PDI1_MIN_SIZE) + rx_pad += rx_alignment; + + pdi1_buffer_size += rx_pad; + /* It is fine if we request more than enough byte to read */ + fake_num_frames = DIV_ROUND_UP(rx_pad, pdi1_buf_size_pre_frame); + fake_size = fake_num_frames * data_per_frame; + + /* find fake pdi0 buffer size */ + pdi0_buffer_size += (fake_num_frames * pdi0_buf_size_pre_frame); + tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment); + pdi0_buffer_size += tx_pad; + } else { /* write */ + /* + * For the write command, the rx data block is 4, and the rx buffer size of a frame + * is 8. So the rx buffer size (pdi0_buffer_size) is always a multiple of rx + * alignment. + */ + tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment); + pdi0_buffer_size += tx_pad; + } dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n", - msg->len, num_frames, data_per_frame); + len, num_frames, data_per_frame); dev_dbg(cdns->dev, "sizes pdi0 %d pdi1 %d tx_bandwidth %d rx_bandwidth %d\n", pdi0_buffer_size, pdi1_buffer_size, tx_dma_bandwidth, rx_dma_bandwidth); @@ -169,15 +237,16 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * } if (!command) { - ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->addr, msg->buf, - msg->len, data_per_frame, + ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->sec, msg->sections, + data_per_frame, sdw->bpt_ctx.dmab_tx_bdl.area, pdi0_buffer_size, &tx_total_bytes); } else { - ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len, + ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->sec, msg->sections, data_per_frame, sdw->bpt_ctx.dmab_tx_bdl.area, - pdi0_buffer_size, &tx_total_bytes); + pdi0_buffer_size, &tx_total_bytes, + fake_size); } if (!ret) @@ -252,11 +321,16 @@ static int intel_ace2x_bpt_send_async(struct sdw_intel *sdw, struct sdw_slave *s struct sdw_bpt_msg *msg) { struct sdw_cdns *cdns = &sdw->cdns; + int len = 0; int ret; + int i; + + for (i = 0; i < msg->sections; i++) + len += msg->sec[i].len; - if (msg->len < INTEL_BPT_MSG_BYTE_MIN) { + if (len < INTEL_BPT_MSG_BYTE_MIN) { dev_err(cdns->dev, "BPT message length %d is less than the minimum bytes %d\n", - msg->len, INTEL_BPT_MSG_BYTE_MIN); + len, INTEL_BPT_MSG_BYTE_MIN); return -EINVAL; } @@ -316,7 +390,7 @@ static int intel_ace2x_bpt_wait(struct sdw_intel *sdw, struct sdw_slave *slave, } else { ret = sdw_cdns_check_read_response(cdns->dev, sdw->bpt_ctx.dmab_rx_bdl.area, sdw->bpt_ctx.pdi1_buffer_size, - msg->buf, msg->len, sdw->bpt_ctx.num_frames, + msg->sec, msg->sections, sdw->bpt_ctx.num_frames, sdw->bpt_ctx.data_per_frame); if (ret < 0) dev_err(cdns->dev, "%s: BPT Read failed %d\n", __func__, ret); diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 5b3078220189..17afc5aa8b44 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -31,6 +31,7 @@ #define SWRM_VERSION_1_5_1 0x01050001 #define SWRM_VERSION_1_7_0 0x01070000 #define SWRM_VERSION_2_0_0 0x02000000 +#define SWRM_VERSION_3_1_0 0x03010000 #define SWRM_COMP_HW_VERSION 0x00 #define SWRM_COMP_CFG_ADDR 0x04 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) @@ -40,6 +41,9 @@ #define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15) #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) +#define SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(17, 10) +#define SWRM_V3_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(23, 18) + #define SWRM_COMP_MASTER_ID 0x104 #define SWRM_V1_3_INTERRUPT_STATUS 0x200 #define SWRM_V2_0_INTERRUPT_STATUS 0x5000 @@ -99,14 +103,15 @@ #define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) #define SWRM_MCP_SLV_STATUS_SZ 2 -#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) -#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_SAMPLECTRL2_BANK(n, m) (0x113C + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1)) + +#define SWRM_DPn_PORT_CTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_PORT_CTRL_2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_BLOCK_CTRL_1(offset, n) (offset + 0x100 * (n - 1)) +#define SWRM_DPn_BLOCK_CTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_PORT_HCTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_BLOCK_CTRL3_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_SAMPLECTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) + #define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740 #define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac @@ -128,7 +133,6 @@ #define MAX_FREQ_NUM 1 #define TIMEOUT_MS 100 #define QCOM_SWRM_MAX_RD_LEN 0x1 -#define QCOM_SDW_MAX_PORTS 14 #define DEFAULT_CLK_FREQ 9600000 #define SWRM_MAX_DAIS 0xF #define SWR_INVALID_PARAM 0xFF @@ -172,6 +176,13 @@ enum { SWRM_REG_CMD_FIFO_RD_CMD, SWRM_REG_CMD_FIFO_STATUS, SWRM_REG_CMD_FIFO_RD_FIFO_ADDR, + SWRM_OFFSET_DP_PORT_CTRL_BANK, + SWRM_OFFSET_DP_PORT_CTRL_2_BANK, + SWRM_OFFSET_DP_BLOCK_CTRL_1, + SWRM_OFFSET_DP_BLOCK_CTRL2_BANK, + SWRM_OFFSET_DP_PORT_HCTRL_BANK, + SWRM_OFFSET_DP_BLOCK_CTRL3_BANK, + SWRM_OFFSET_DP_SAMPLECTRL2_BANK, }; struct qcom_swrm_ctrl { @@ -195,6 +206,7 @@ struct qcom_swrm_ctrl { int wake_irq; int num_din_ports; int num_dout_ports; + int nports; int cols_index; int rows_index; unsigned long port_mask; @@ -202,14 +214,13 @@ struct qcom_swrm_ctrl { u8 rcmd_id; u8 wcmd_id; /* Port numbers are 1 - 14 */ - struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS + 1]; + struct qcom_swrm_port_config *pconfig; struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); u32 slave_status; u32 wr_fifo_depth; - u32 rd_fifo_depth; bool clock_stop_not_supported; }; @@ -231,6 +242,13 @@ static const unsigned int swrm_v1_3_reg_layout[] = { [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V1_3_CMD_FIFO_RD_CMD, [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V1_3_CMD_FIFO_STATUS, [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR, + [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124, + [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128, + [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c, + [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130, + [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134, + [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138, + [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c, }; static const struct qcom_swrm_data swrm_v1_3_data = { @@ -265,6 +283,13 @@ static const unsigned int swrm_v2_0_reg_layout[] = { [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD, [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS, [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR, + [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124, + [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128, + [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c, + [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130, + [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134, + [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138, + [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c, }; static const struct qcom_swrm_data swrm_v2_0_data = { @@ -275,6 +300,32 @@ static const struct qcom_swrm_data swrm_v2_0_data = { .reg_layout = swrm_v2_0_reg_layout, }; +static const unsigned int swrm_v3_0_reg_layout[] = { + [SWRM_REG_FRAME_GEN_ENABLED] = SWRM_V2_0_LINK_STATUS, + [SWRM_REG_INTERRUPT_STATUS] = SWRM_V2_0_INTERRUPT_STATUS, + [SWRM_REG_INTERRUPT_MASK_ADDR] = 0, /* Not present */ + [SWRM_REG_INTERRUPT_CLEAR] = SWRM_V2_0_INTERRUPT_CLEAR, + [SWRM_REG_INTERRUPT_CPU_EN] = SWRM_V2_0_INTERRUPT_CPU_EN, + [SWRM_REG_CMD_FIFO_WR_CMD] = SWRM_V2_0_CMD_FIFO_WR_CMD, + [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD, + [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS, + [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR, + [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1224, + [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1228, + [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x122c, + [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1230, + [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1234, + [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1238, + [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x123c, +}; + +static const struct qcom_swrm_data swrm_v3_0_data = { + .default_rows = 50, + .default_cols = 16, + .sw_clk_gate_required = true, + .max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR, + .reg_layout = swrm_v3_0_reg_layout, +}; #define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus) static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, @@ -898,8 +949,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) swrm_wait_for_frame_gen_enabled(ctrl); ctrl->slave_status = 0; ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); - ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val); - ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); + + if (ctrl->version >= SWRM_VERSION_3_1_0) + ctrl->wr_fifo_depth = FIELD_GET(SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH, val); + else + ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); return 0; } @@ -966,10 +1020,10 @@ static int qcom_swrm_port_params(struct sdw_bus *bus, unsigned int bank) { struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL_1]; - return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num), - p_params->bps - 1); - + return ctrl->reg_write(ctrl, SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num), + p_params->bps - 1); } static int qcom_swrm_transport_params(struct sdw_bus *bus, @@ -979,9 +1033,11 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct qcom_swrm_port_config *pcfg; u32 value; - int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); + int reg, offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK]; int ret; + reg = SWRM_DPn_PORT_CTRL_BANK(offset, params->port_num, bank); + pcfg = &ctrl->pconfig[params->port_num]; value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; @@ -993,15 +1049,19 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, goto err; if (pcfg->si > 0xff) { + offset = ctrl->reg_layout[SWRM_OFFSET_DP_SAMPLECTRL2_BANK]; value = (pcfg->si >> 8) & 0xff; - reg = SWRM_DP_SAMPLECTRL2_BANK(params->port_num, bank); + reg = SWRM_DPn_SAMPLECTRL2_BANK(offset, params->port_num, bank); + ret = ctrl->reg_write(ctrl, reg, value); if (ret) goto err; } if (pcfg->lane_control != SWR_INVALID_PARAM) { - reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_2_BANK]; + reg = SWRM_DPn_PORT_CTRL_2_BANK(offset, params->port_num, bank); + value = pcfg->lane_control; ret = ctrl->reg_write(ctrl, reg, value); if (ret) @@ -1009,20 +1069,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, } if (pcfg->blk_group_count != SWR_INVALID_PARAM) { - reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK]; + + reg = SWRM_DPn_BLOCK_CTRL2_BANK(offset, params->port_num, bank); + value = pcfg->blk_group_count; ret = ctrl->reg_write(ctrl, reg, value); if (ret) goto err; } - if (pcfg->hstart != SWR_INVALID_PARAM - && pcfg->hstop != SWR_INVALID_PARAM) { - reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_HCTRL_BANK]; + reg = SWRM_DPn_PORT_HCTRL_BANK(offset, params->port_num, bank); + + if (pcfg->hstart != SWR_INVALID_PARAM && pcfg->hstop != SWR_INVALID_PARAM) { value = (pcfg->hstop << 4) | pcfg->hstart; ret = ctrl->reg_write(ctrl, reg, value); } else { - reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL; ret = ctrl->reg_write(ctrl, reg, value); } @@ -1031,7 +1094,8 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, goto err; if (pcfg->bp_mode != SWR_INVALID_PARAM) { - reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK]; + reg = SWRM_DPn_BLOCK_CTRL3_BANK(offset, params->port_num, bank); ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode); } @@ -1043,9 +1107,12 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus, struct sdw_enable_ch *enable_ch, unsigned int bank) { - u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank); + u32 reg; struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); u32 val; + u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK]; + + reg = SWRM_DPn_PORT_CTRL_BANK(offset, enable_ch->port_num, bank); ctrl->reg_read(ctrl, reg, &val); @@ -1155,7 +1222,6 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, struct snd_pcm_hw_params *params, int direction) { - struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS]; struct sdw_stream_config sconfig; struct sdw_master_runtime *m_rt; struct sdw_slave_runtime *s_rt; @@ -1164,6 +1230,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, unsigned long *port_mask; int maxport, pn, nports = 0, ret = 0; unsigned int m_port; + struct sdw_port_config *pconfig __free(kfree) = kcalloc(ctrl->nports, + sizeof(*pconfig), GFP_KERNEL); + if (!pconfig) + return -ENOMEM; if (direction == SNDRV_PCM_STREAM_CAPTURE) sconfig.direction = SDW_DATA_DIR_TX; @@ -1188,8 +1258,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, continue; port_mask = &ctrl->port_mask; - maxport = ctrl->num_dout_ports + ctrl->num_din_ports; - + maxport = ctrl->nports; list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { slave = s_rt->slave; @@ -1349,17 +1418,8 @@ static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl) static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) { struct device_node *np = ctrl->dev->of_node; - u8 off1[QCOM_SDW_MAX_PORTS]; - u8 off2[QCOM_SDW_MAX_PORTS]; - u16 si[QCOM_SDW_MAX_PORTS]; - u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; - u8 hstart[QCOM_SDW_MAX_PORTS]; - u8 hstop[QCOM_SDW_MAX_PORTS]; - u8 word_length[QCOM_SDW_MAX_PORTS]; - u8 blk_group_count[QCOM_SDW_MAX_PORTS]; - u8 lane_control[QCOM_SDW_MAX_PORTS]; - int i, ret, nports, val; - bool si_16 = false; + struct qcom_swrm_port_config *pcfg; + int i, ret, val; ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); @@ -1367,88 +1427,78 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val); ret = of_property_read_u32(np, "qcom,din-ports", &val); - if (ret) - return ret; - - if (val > ctrl->num_din_ports) - return -EINVAL; + if (!ret) { /* only if present */ + if (val != ctrl->num_din_ports) { + dev_err(ctrl->dev, "din-ports (%d) mismatch with controller (%d)", + val, ctrl->num_din_ports); + } - ctrl->num_din_ports = val; + ctrl->num_din_ports = val; + } ret = of_property_read_u32(np, "qcom,dout-ports", &val); - if (ret) - return ret; + if (!ret) { /* only if present */ + if (val != ctrl->num_dout_ports) { + dev_err(ctrl->dev, "dout-ports (%d) mismatch with controller (%d)", + val, ctrl->num_dout_ports); + } - if (val > ctrl->num_dout_ports) - return -EINVAL; + ctrl->num_dout_ports = val; + } - ctrl->num_dout_ports = val; + ctrl->nports = ctrl->num_dout_ports + ctrl->num_din_ports; - nports = ctrl->num_dout_ports + ctrl->num_din_ports; - if (nports > QCOM_SDW_MAX_PORTS) - return -EINVAL; + ctrl->pconfig = devm_kcalloc(ctrl->dev, ctrl->nports + 1, + sizeof(*ctrl->pconfig), GFP_KERNEL); + if (!ctrl->pconfig) + return -ENOMEM; - /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ set_bit(0, &ctrl->port_mask); + /* Valid port numbers are from 1, so mask out port 0 explicitly */ + for (i = 0; i < ctrl->nports; i++) { + pcfg = &ctrl->pconfig[i + 1]; - ret = of_property_read_u8_array(np, "qcom,ports-offset1", - off1, nports); - if (ret) - return ret; - - ret = of_property_read_u8_array(np, "qcom,ports-offset2", - off2, nports); - if (ret) - return ret; - - ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low", - (u8 *)si, nports); - if (ret) { - ret = of_property_read_u16_array(np, "qcom,ports-sinterval", - si, nports); + ret = of_property_read_u8_index(np, "qcom,ports-offset1", i, &pcfg->off1); if (ret) return ret; - si_16 = true; - } - ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", - bp_mode, nports); - if (ret) { - if (ctrl->version <= SWRM_VERSION_1_3_0) - memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - else + ret = of_property_read_u8_index(np, "qcom,ports-offset2", i, &pcfg->off2); + if (ret) return ret; - } - memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports); + ret = of_property_read_u8_index(np, "qcom,ports-sinterval-low", i, (u8 *)&pcfg->si); + if (ret) { + ret = of_property_read_u16_index(np, "qcom,ports-sinterval", i, &pcfg->si); + if (ret) + return ret; + } + + ret = of_property_read_u8_index(np, "qcom,ports-block-pack-mode", + i, &pcfg->bp_mode); + if (ret) { + if (ctrl->version <= SWRM_VERSION_1_3_0) + pcfg->bp_mode = SWR_INVALID_PARAM; + else + return ret; + } + + /* Optional properties */ + pcfg->hstart = SWR_INVALID_PARAM; + pcfg->hstop = SWR_INVALID_PARAM; + pcfg->word_length = SWR_INVALID_PARAM; + pcfg->blk_group_count = SWR_INVALID_PARAM; + pcfg->lane_control = SWR_INVALID_PARAM; - memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports); + of_property_read_u8_index(np, "qcom,ports-hstart", i, &pcfg->hstart); - memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports); + of_property_read_u8_index(np, "qcom,ports-hstop", i, &pcfg->hstop); - memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports); + of_property_read_u8_index(np, "qcom,ports-word-length", i, &pcfg->word_length); - memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports); + of_property_read_u8_index(np, "qcom,ports-block-group-count", + i, &pcfg->blk_group_count); - for (i = 0; i < nports; i++) { - /* Valid port number range is from 1-14 */ - if (si_16) - ctrl->pconfig[i + 1].si = si[i]; - else - ctrl->pconfig[i + 1].si = ((u8 *)si)[i]; - ctrl->pconfig[i + 1].off1 = off1[i]; - ctrl->pconfig[i + 1].off2 = off2[i]; - ctrl->pconfig[i + 1].bp_mode = bp_mode[i]; - ctrl->pconfig[i + 1].hstart = hstart[i]; - ctrl->pconfig[i + 1].hstop = hstop[i]; - ctrl->pconfig[i + 1].word_length = word_length[i]; - ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i]; - ctrl->pconfig[i + 1].lane_control = lane_control[i]; + of_property_read_u8_index(np, "qcom,ports-lane-control", i, &pcfg->lane_control); } return 0; @@ -1769,6 +1819,7 @@ static const struct of_device_id qcom_swrm_of_match[] = { { .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data }, { .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data }, { .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data }, + { .compatible = "qcom,soundwire-v3.1.0", .data = &swrm_v3_0_data }, {/* sentinel */}, }; diff --git a/drivers/spi/spi-microchip-core-spi.c b/drivers/spi/spi-microchip-core-spi.c index 98bf0e6cd00e..89e40fc45d73 100644 --- a/drivers/spi/spi-microchip-core-spi.c +++ b/drivers/spi/spi-microchip-core-spi.c @@ -387,6 +387,7 @@ static int mchp_corespi_probe(struct platform_device *pdev) ret = devm_spi_register_controller(dev, host); if (ret) { + mchp_corespi_disable_ints(spi); mchp_corespi_disable(spi); return dev_err_probe(dev, ret, "unable to register host for CoreSPI controller\n"); } diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index b8457477cee9..9f167ff8da7b 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -5,8 +5,7 @@ * Copyright (C) 2011 Chris Boot <bootc@bootc.net> */ -#define KMSG_COMPONENT "sbp_target" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#define pr_fmt(fmt) "sbp_target: " fmt #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e8b7955d40f2..50d21888a0c9 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1524,6 +1524,7 @@ target_cmd_init_cdb(struct se_cmd *cmd, unsigned char *cdb, gfp_t gfp) if (scsi_command_size(cdb) > sizeof(cmd->__t_task_cdb)) { cmd->t_task_cdb = kzalloc(scsi_command_size(cdb), gfp); if (!cmd->t_task_cdb) { + cmd->t_task_cdb = &cmd->__t_task_cdb[0]; pr_err("Unable to allocate cmd->t_task_cdb" " %u > sizeof(cmd->__t_task_cdb): %lu ops\n", scsi_command_size(cdb), diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index 90226f72c158..f662e7ce71f1 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -6,6 +6,7 @@ menuconfig SCSI_UFSHCD tristate "Universal Flash Storage Controller" depends on SCSI && SCSI_DMA + depends on RPMB || !RPMB select PM_DEVFREQ select DEVFREQ_GOV_SIMPLE_ONDEMAND select NLS diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 040a0ceb170a..80c0b49f30b0 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1455,15 +1455,14 @@ out: static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err) { up_write(&hba->clk_scaling_lock); + mutex_unlock(&hba->wb_mutex); + blk_mq_unquiesce_tagset(&hba->host->tag_set); + mutex_unlock(&hba->host->scan_mutex); /* Enable Write Booster if current gear requires it else disable it */ if (ufshcd_enable_wb_if_scaling_up(hba) && !err) ufshcd_wb_toggle(hba, hba->pwr_info.gear_rx >= hba->clk_scaling.wb_gear); - mutex_unlock(&hba->wb_mutex); - - blk_mq_unquiesce_tagset(&hba->host->tag_set); - mutex_unlock(&hba->host->scan_mutex); ufshcd_release(hba); } @@ -6504,6 +6503,11 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend) static void ufshcd_err_handling_prepare(struct ufs_hba *hba) { + /* + * A WLUN resume failure could potentially lead to the HBA being + * runtime suspended, so take an extra reference on hba->dev. + */ + pm_runtime_get_sync(hba->dev); ufshcd_rpm_get_sync(hba); if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) || hba->is_sys_suspended) { @@ -6543,6 +6547,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) if (ufshcd_is_clkscaling_supported(hba)) ufshcd_clk_scaling_suspend(hba, false); ufshcd_rpm_put(hba); + pm_runtime_put(hba->dev); } static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) @@ -6557,28 +6562,42 @@ static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) #ifdef CONFIG_PM static void ufshcd_recover_pm_error(struct ufs_hba *hba) { + struct scsi_target *starget = hba->ufs_device_wlun->sdev_target; struct Scsi_Host *shost = hba->host; struct scsi_device *sdev; struct request_queue *q; - int ret; + bool resume_sdev_queues = false; hba->is_sys_suspended = false; + /* - * Set RPM status of wlun device to RPM_ACTIVE, - * this also clears its runtime error. + * Ensure the parent's error status is cleared before proceeding + * to the child, as the parent must be active to activate the child. */ - ret = pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev); + if (hba->dev->power.runtime_error) { + /* hba->dev has no functional parent thus simplily set RPM_ACTIVE */ + pm_runtime_set_active(hba->dev); + resume_sdev_queues = true; + } + + if (hba->ufs_device_wlun->sdev_gendev.power.runtime_error) { + /* + * starget, parent of wlun, might be suspended if wlun resume failed. + * Make sure parent is resumed before set child (wlun) active. + */ + pm_runtime_get_sync(&starget->dev); + pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev); + pm_runtime_put_sync(&starget->dev); + resume_sdev_queues = true; + } - /* hba device might have a runtime error otherwise */ - if (ret) - ret = pm_runtime_set_active(hba->dev); /* * If wlun device had runtime error, we also need to resume those * consumer scsi devices in case any of them has failed to be * resumed due to supplier runtime resume failure. This is to unblock * blk_queue_enter in case there are bios waiting inside it. */ - if (!ret) { + if (resume_sdev_queues) { shost_for_each_device(sdev, shost) { q = sdev->request_queue; if (q->dev && (q->rpm_status == RPM_SUSPENDED || @@ -6679,19 +6698,22 @@ static void ufshcd_err_handler(struct work_struct *work) hba->saved_uic_err, hba->force_reset, ufshcd_is_link_broken(hba) ? "; link is broken" : ""); - /* - * Use ufshcd_rpm_get_noresume() here to safely perform link recovery - * even if an error occurs during runtime suspend or runtime resume. - * This avoids potential deadlocks that could happen if we tried to - * resume the device while a PM operation is already in progress. - */ - ufshcd_rpm_get_noresume(hba); - if (hba->pm_op_in_progress) { - ufshcd_link_recovery(hba); + if (hba->ufs_device_wlun) { + /* + * Use ufshcd_rpm_get_noresume() here to safely perform link + * recovery even if an error occurs during runtime suspend or + * runtime resume. This avoids potential deadlocks that could + * happen if we tried to resume the device while a PM operation + * is already in progress. + */ + ufshcd_rpm_get_noresume(hba); + if (hba->pm_op_in_progress) { + ufshcd_link_recovery(hba); + ufshcd_rpm_put(hba); + return; + } ufshcd_rpm_put(hba); - return; } - ufshcd_rpm_put(hba); down(&hba->host_sem); spin_lock_irqsave(hba->host->host_lock, flags); diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 8d119b3223cb..8ebee0cc5313 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1769,10 +1769,9 @@ static void ufs_qcom_dump_testbus(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); int i, j, nminor = 0, testbus_len = 0; - u32 *testbus __free(kfree) = NULL; char *prefix; - testbus = kmalloc_array(256, sizeof(u32), GFP_KERNEL); + u32 *testbus __free(kfree) = kmalloc_array(256, sizeof(u32), GFP_KERNEL); if (!testbus) return; @@ -1794,13 +1793,12 @@ static void ufs_qcom_dump_testbus(struct ufs_hba *hba) static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, const char *prefix, void __iomem *base) { - u32 *regs __free(kfree) = NULL; size_t pos; if (offset % 4 != 0 || len % 4 != 0) return -EINVAL; - regs = kzalloc(len, GFP_ATOMIC); + u32 *regs __free(kfree) = kzalloc(len, GFP_ATOMIC); if (!regs) return -ENOMEM; |
