From 43df43e6ba139e6cd77ea31ca27efc67ea2df44b Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 23 Aug 2017 16:46:12 +0300 Subject: i2c: designware: Don't set SCL timings and speed mode when in slave mode According to data sheet SCL timing parameters and DW_IC_CON SPEED mode bits are not used when operating in slave mode. Signed-off-by: Jarkko Nikula Tested-by: Luis Oliveira Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 11 ----- drivers/i2c/busses/i2c-designware-slave.c | 64 ----------------------------- 2 files changed, 75 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 58add69a441c..293f586d78d2 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -201,17 +201,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev) DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED; dev->mode = DW_IC_SLAVE; - - switch (dev->clk_freq) { - case 100000: - dev->slave_cfg |= DW_IC_CON_SPEED_STD; - break; - case 3400000: - dev->slave_cfg |= DW_IC_CON_SPEED_HIGH; - break; - default: - dev->slave_cfg |= DW_IC_CON_SPEED_FAST; - } } static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index ea9578ab19a1..d42558d1b002 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -51,9 +51,7 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) */ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) { - u32 sda_falling_time, scl_falling_time; u32 reg, comp_param1; - u32 hcnt, lcnt; int ret; ret = i2c_dw_acquire_lock(dev); @@ -79,68 +77,6 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) /* Disable the adapter. */ __i2c_dw_enable_and_wait(dev, false); - /* Set standard and fast speed deviders for high/low periods. */ - sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ - scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ - - /* Set SCL timing parameters for standard-mode. */ - if (dev->ss_hcnt && dev->ss_lcnt) { - hcnt = dev->ss_hcnt; - lcnt = dev->ss_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), - 4000, /* tHD;STA = tHIGH = 4.0 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), - 4700, /* tLOW = 4.7 us */ - scl_falling_time, - 0); /* No offset */ - } - dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); - dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - - /* Set SCL timing parameters for fast-mode or fast-mode plus. */ - if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { - hcnt = dev->fp_hcnt; - lcnt = dev->fp_lcnt; - } else if (dev->fs_hcnt && dev->fs_lcnt) { - hcnt = dev->fs_hcnt; - lcnt = dev->fs_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), - 600, /* tHD;STA = tHIGH = 0.6 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), - 1300, /* tLOW = 1.3 us */ - scl_falling_time, - 0); /* No offset */ - } - dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); - dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - - if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) == - DW_IC_CON_SPEED_HIGH) { - if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) - != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) { - dev_err(dev->dev, "High Speed not supported!\n"); - dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK; - dev->slave_cfg |= DW_IC_CON_SPEED_FAST; - } else if (dev->hs_hcnt && dev->hs_lcnt) { - hcnt = dev->hs_hcnt; - lcnt = dev->hs_lcnt; - dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); - dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", - hcnt, lcnt); - } - } - /* Configure SDA Hold Time if required. */ reg = dw_readl(dev, DW_IC_COMP_VERSION); if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { -- cgit From 3991c5c80beaf7eb9bce61e0b2f8f449e351a38e Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:24 +0800 Subject: i2c: Switch to using gpiod interface for gpio bus recovery Currently the i2c gpio recovery code uses gpio integer interface instead of the gpiod. This change switch the core code to use the gpiod while still retaining compatibility with the gpio integer interface. This will allow individual driver to be updated and tested individual to switch to using the gpiod interface. Reviewed-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 706164b4c5be..fdc6a9d1394e 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -134,17 +134,17 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) /* i2c bus recovery routines */ static int get_scl_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->scl_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->scl_gpiod); } static void set_scl_gpio_value(struct i2c_adapter *adap, int val) { - gpio_set_value(adap->bus_recovery_info->scl_gpio, val); + gpiod_set_value_cansleep(adap->bus_recovery_info->scl_gpiod, val); } static int get_sda_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->sda_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) @@ -159,6 +159,7 @@ static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); return ret; } + bri->scl_gpiod = gpio_to_desc(bri->scl_gpio); if (bri->get_sda) { if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { @@ -167,6 +168,7 @@ static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) bri->sda_gpio); bri->get_sda = NULL; } + bri->sda_gpiod = gpio_to_desc(bri->sda_gpio); } return ret; @@ -176,10 +178,13 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - if (bri->get_sda) + if (bri->get_sda) { gpio_free(bri->sda_gpio); + bri->sda_gpiod = NULL; + } gpio_free(bri->scl_gpio); + bri->scl_gpiod = NULL; } /* @@ -277,6 +282,14 @@ static void i2c_init_recovery(struct i2c_adapter *adap) goto err; } + if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_recovery) { + bri->get_scl = get_scl_gpio_value; + bri->set_scl = set_scl_gpio_value; + if (bri->sda_gpiod) + bri->get_sda = get_sda_gpio_value; + return; + } + /* Generic GPIO recovery */ if (bri->recover_bus == i2c_generic_gpio_recovery) { if (!gpio_is_valid(bri->scl_gpio)) { -- cgit From a34a0b6da22540d19e578131bbb60994892473d3 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:25 +0800 Subject: i2c: designware: move i2c_dw_plat_prepare_clk to common Move the i2c_dw_plat_prepare_clk funciton to common file in preparation for its use also by the master driver. Acked-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 13 +++++++++++++ drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-platdrv.c | 12 ------------ 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index d1a69372432f..b79f34245930 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -21,6 +21,7 @@ * ---------------------------------------------------------------------------- * */ +#include #include #include #include @@ -185,6 +186,18 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } +int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) +{ + if (IS_ERR(i_dev->clk)) + return PTR_ERR(i_dev->clk); + + if (prepare) + return clk_prepare_enable(i_dev->clk); + + clk_disable_unprepare(i_dev->clk); + return 0; +} + int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) { int ret; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 21bf619a86c5..e80a14c40347 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -301,6 +301,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); +int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 293f586d78d2..6a3fd8d7c273 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -203,18 +203,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev) dev->mode = DW_IC_SLAVE; } -static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) -{ - if (IS_ERR(i_dev->clk)) - return PTR_ERR(i_dev->clk); - - if (prepare) - return clk_prepare_enable(i_dev->clk); - - clk_disable_unprepare(i_dev->clk); - return 0; -} - static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) { u32 param, tx_fifo_depth, rx_fifo_depth; -- cgit From 0326f9f801b2411811906361db870ccdada98b92 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:26 +0800 Subject: i2c: designware: rename i2c_dw_plat_prepare_clk to i2c_dw_prepare_clk For consistency with the rest of the file rename function and parameter to be consistent with the reset of the common file. Acked-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 10 +++++----- drivers/i2c/busses/i2c-designware-core.h | 2 +- drivers/i2c/busses/i2c-designware-platdrv.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index b79f34245930..3d684c6650b5 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -186,15 +186,15 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } -int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare) { - if (IS_ERR(i_dev->clk)) - return PTR_ERR(i_dev->clk); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); if (prepare) - return clk_prepare_enable(i_dev->clk); + return clk_prepare_enable(dev->clk); - clk_disable_unprepare(i_dev->clk); + clk_disable_unprepare(dev->clk); return 0; } diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index e80a14c40347..33c6c8f03061 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -301,7 +301,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); -int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare); +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 6a3fd8d7c273..6e0fd94faba1 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -332,7 +332,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) i2c_dw_configure_master(dev); dev->clk = devm_clk_get(&pdev->dev, NULL); - if (!i2c_dw_plat_prepare_clk(dev, true)) { + if (!i2c_dw_prepare_clk(dev, true)) { dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; if (!dev->sda_hold_time && ht) @@ -436,7 +436,7 @@ static int dw_i2c_plat_suspend(struct device *dev) } i_dev->disable(i_dev); - i2c_dw_plat_prepare_clk(i_dev, false); + i2c_dw_prepare_clk(i_dev, false); i_dev->suspended = true; @@ -455,7 +455,7 @@ static int dw_i2c_plat_resume(struct device *dev) return 0; } - i2c_dw_plat_prepare_clk(i_dev, true); + i2c_dw_prepare_clk(i_dev, true); i_dev->init(i_dev); i_dev->suspended = false; -- cgit From ca382f5b38f367b656c8fd9a0fb93d8f54843520 Mon Sep 17 00:00:00 2001 From: Tim Sander Date: Thu, 2 Nov 2017 10:40:27 +0800 Subject: i2c: designware: add i2c gpio recovery option This patch contains much input from Phil Reid and has been tested on Intel/Altera Cyclone V SOC Hardware with Altera GPIO's for the SCL and SDA GPIO's. Acked-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Tim Sander Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 6 +++- drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-master.c | 57 ++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 3d684c6650b5..6b82809647dc 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -230,7 +230,11 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { if (timeout <= 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + i2c_recover_bus(&dev->adapter); + + if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) + return -ETIMEDOUT; + return 0; } timeout--; usleep_range(1000, 1100); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 33c6c8f03061..d58a336521bf 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -286,6 +286,7 @@ struct dw_i2c_dev { void (*disable_int)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); int mode; + struct i2c_bus_recovery_info rinfo; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 418c233075d3..ae691884d071 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -25,11 +25,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "i2c-designware-core.h" @@ -443,6 +445,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ + i2c_recover_bus(&dev->adapter); i2c_dw_init_master(dev); ret = -ETIMEDOUT; goto done; @@ -613,6 +616,56 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +static void i2c_dw_prepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_disable(dev); + reset_control_assert(dev->rst); + i2c_dw_prepare_clk(dev, false); +} + +static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_prepare_clk(dev, true); + reset_control_deassert(dev->rst); + i2c_dw_init_master(dev); +} + +static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) +{ + struct i2c_bus_recovery_info *rinfo = &dev->rinfo; + struct i2c_adapter *adap = &dev->adapter; + struct gpio_desc *gpio; + int r; + + gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); + if (r == -ENOENT) + return 0; + return r; + } + rinfo->scl_gpiod = gpio; + + gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + rinfo->sda_gpiod = gpio; + + rinfo->recover_bus = i2c_generic_scl_recovery; + rinfo->prepare_recovery = i2c_dw_prepare_recovery; + rinfo->unprepare_recovery = i2c_dw_unprepare_recovery; + adap->bus_recovery_info = rinfo; + + dev_info(dev->dev, "running with gpio recovery mode! scl%s", + rinfo->sda_gpiod ? ",sda" : ""); + + return 0; +} + int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; @@ -652,6 +705,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) return ret; } + ret = i2c_dw_init_recovery_info(dev); + if (ret) + return ret; + /* * Increment PM usage count during adapter registration in order to * avoid possible spurious runtime suspend when adapter device is -- cgit From ad36a27959cabb27dfde35ff103d03b22f6ddb36 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:28 +0800 Subject: i2c: imx: switch to using gpiod for bus recovery gpios Change the driver to use the gpio descriptors for the bus recovery information instead of the deprecated integer interface. Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f96830ffd9f1..c4cf26571b66 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1006,26 +1006,26 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, PINCTRL_STATE_DEFAULT); i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, "gpio"); - rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0); - rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0); + rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_OUT_HIGH); + rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_IN); - if (rinfo->sda_gpio == -EPROBE_DEFER || - rinfo->scl_gpio == -EPROBE_DEFER) { + if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER || + PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) { return -EPROBE_DEFER; - } else if (!gpio_is_valid(rinfo->sda_gpio) || - !gpio_is_valid(rinfo->scl_gpio) || + } else if (IS_ERR(rinfo->sda_gpiod) || + IS_ERR(rinfo->scl_gpiod) || IS_ERR(i2c_imx->pinctrl_pins_default) || IS_ERR(i2c_imx->pinctrl_pins_gpio)) { dev_dbg(&pdev->dev, "recovery information incomplete\n"); return 0; } - dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", - rinfo->scl_gpio, rinfo->sda_gpio); + dev_dbg(&pdev->dev, "using scl%s for recovery\n", + rinfo->sda_gpiod ? ",sda" : ""); rinfo->prepare_recovery = i2c_imx_prepare_recovery; rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; - rinfo->recover_bus = i2c_generic_gpio_recovery; + rinfo->recover_bus = i2c_generic_scl_recovery; i2c_imx->adapter.bus_recovery_info = rinfo; return 0; -- cgit From cd2428c368a66c4d61cd416a4f0ad453ce6d57cd Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:29 +0800 Subject: i2c: davinci: switch to using gpiod for bus recovery gpios Change the driver to use the gpio descriptors for the bus recovery information instead of the deprecated integer interface. Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Reviewed-by: Sekhar Nori Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-davinci.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 2ead9b9eebb7..2afb12a89eb3 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -294,7 +294,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) } /* - * This routine does i2c bus recovery by using i2c_generic_gpio_recovery + * This routine does i2c bus recovery by using i2c_generic_scl_recovery * which is provided by I2C Bus recovery infrastructure. */ static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap) @@ -316,7 +316,7 @@ static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap) } static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = { - .recover_bus = i2c_generic_gpio_recovery, + .recover_bus = i2c_generic_scl_recovery, .prepare_recovery = davinci_i2c_prepare_recovery, .unprepare_recovery = davinci_i2c_unprepare_recovery, }; @@ -769,6 +769,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) struct davinci_i2c_dev *dev; struct i2c_adapter *adap; struct resource *mem; + struct i2c_bus_recovery_info *rinfo; int r, irq; irq = platform_get_irq(pdev, 0); @@ -869,9 +870,18 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (dev->pdata->has_pfunc) adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; else if (dev->pdata->scl_pin) { - adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info; - adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin; - adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin; + rinfo = &davinci_i2c_gpio_recovery_info; + adap->bus_recovery_info = rinfo; + r = gpio_request_one(dev->pdata->scl_pin, GPIOF_OPEN_DRAIN | + GPIOF_OUT_INIT_HIGH, "i2c-scl"); + if (r) + goto err_unuse_clocks; + rinfo->scl_gpiod = gpio_to_desc(dev->pdata->scl_pin); + + r = gpio_request_one(dev->pdata->sda_pin, GPIOF_IN, "i2c-sda"); + if (r) + goto err_unuse_clocks; + rinfo->sda_gpiod = gpio_to_desc(dev->pdata->scl_pin); } adap->nr = pdev->id; -- cgit From e1eb7d28c0753ec3e5ff9dce7880c243ffdfd4b3 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:30 +0800 Subject: i2c: remove legacy integer scl/sda gpio for recovery Remove all reference to code related to using integer based ids for scl/sda gpio for bus recovery. All in tree drivers are now using the gpio descriptors to specific the required gpios. Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Reviewed-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 78 ++------------------------------------------- 1 file changed, 2 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index fdc6a9d1394e..54ffc8da40df 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -147,46 +147,6 @@ static int get_sda_gpio_value(struct i2c_adapter *adap) return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } -static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) -{ - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - struct device *dev = &adap->dev; - int ret = 0; - - ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN | - GPIOF_OUT_INIT_HIGH, "i2c-scl"); - if (ret) { - dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); - return ret; - } - bri->scl_gpiod = gpio_to_desc(bri->scl_gpio); - - if (bri->get_sda) { - if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { - /* work without SDA polling */ - dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n", - bri->sda_gpio); - bri->get_sda = NULL; - } - bri->sda_gpiod = gpio_to_desc(bri->sda_gpio); - } - - return ret; -} - -static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) -{ - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - - if (bri->get_sda) { - gpio_free(bri->sda_gpio); - bri->sda_gpiod = NULL; - } - - gpio_free(bri->scl_gpio); - bri->scl_gpiod = NULL; -} - /* * We are generating clock pulses. ndelay() determines durating of clk pulses. * We will generate clock with rate 100 KHz and so duration of both clock levels @@ -195,7 +155,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) #define RECOVERY_NDELAY 5000 #define RECOVERY_CLK_CNT 9 -static int i2c_generic_recovery(struct i2c_adapter *adap) +int i2c_generic_scl_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; int i = 0, val = 1, ret = 0; @@ -237,28 +197,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) return ret; } - -int i2c_generic_scl_recovery(struct i2c_adapter *adap) -{ - return i2c_generic_recovery(adap); -} EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); -int i2c_generic_gpio_recovery(struct i2c_adapter *adap) -{ - int ret; - - ret = i2c_get_gpios_for_recovery(adap); - if (ret) - return ret; - - ret = i2c_generic_recovery(adap); - i2c_put_gpios_for_recovery(adap); - - return ret; -} -EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery); - int i2c_recover_bus(struct i2c_adapter *adap) { if (!adap->bus_recovery_info) @@ -290,21 +230,7 @@ static void i2c_init_recovery(struct i2c_adapter *adap) return; } - /* Generic GPIO recovery */ - if (bri->recover_bus == i2c_generic_gpio_recovery) { - if (!gpio_is_valid(bri->scl_gpio)) { - err_str = "invalid SCL gpio"; - goto err; - } - - if (gpio_is_valid(bri->sda_gpio)) - bri->get_sda = get_sda_gpio_value; - else - bri->get_sda = NULL; - - bri->get_scl = get_scl_gpio_value; - bri->set_scl = set_scl_gpio_value; - } else if (bri->recover_bus == i2c_generic_scl_recovery) { + if (bri->recover_bus == i2c_generic_scl_recovery) { /* Generic SCL recovery */ if (!bri->set_scl || !bri->get_scl) { err_str = "no {get|set}_scl() found"; -- cgit From f289800af1fd4379403f2630e7e9420401a4cd8e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:27 +0100 Subject: i2c: sh_mobile: remove redundant initialization Following the documentation, we initialize the HW before each START in start_ch(). No need to do the same in activate_ch(). Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index c03acdf71397..0ac152586e74 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -303,16 +303,6 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) /* Wake up device and enable clock */ pm_runtime_get_sync(pd->dev); clk_prepare_enable(pd->clk); - - /* Enable channel and configure rx ack */ - iic_set_clr(pd, ICCR, ICCR_ICE, 0); - - /* Mask all interrupts */ - iic_wr(pd, ICIC, 0); - - /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl & 0xff); - iic_wr(pd, ICCH, pd->icch & 0xff); } static void deactivate_ch(struct sh_mobile_i2c_data *pd) -- cgit From 3f3a513985ce55d69922cc9b5a0e095432cdfbc4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:28 +0100 Subject: i2c: sh_mobile: remove redundant deinitialization No need to clear the interrupt registers because right after that we disable the IP core which will reload registers with their initial values anyhow. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 0ac152586e74..cbaed24fb18f 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -307,10 +307,6 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) static void deactivate_ch(struct sh_mobile_i2c_data *pd) { - /* Clear/disable interrupts */ - iic_wr(pd, ICSR, 0); - iic_wr(pd, ICIC, 0); - /* Disable channel */ iic_set_clr(pd, ICCR, 0, ICCR_ICE); -- cgit From 91a5e63e3f9879e5030064a3c0d23c3777c4f4d0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:29 +0100 Subject: i2c: sh_mobile: manually "inline" two short functions Those two functions are very short and only called once. The code becomes easier to understand if the code is directly put into the main xfer function. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index cbaed24fb18f..02c2912bebb4 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -298,23 +298,6 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) return 0; } -static void activate_ch(struct sh_mobile_i2c_data *pd) -{ - /* Wake up device and enable clock */ - pm_runtime_get_sync(pd->dev); - clk_prepare_enable(pd->clk); -} - -static void deactivate_ch(struct sh_mobile_i2c_data *pd) -{ - /* Disable channel */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); - - /* Disable clock and mark device as idle */ - clk_disable_unprepare(pd->clk); - pm_runtime_put_sync(pd->dev); -} - static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op op, unsigned char data) { @@ -717,7 +700,9 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, int i; long timeout; - activate_ch(pd); + /* Wake up device and enable clock */ + pm_runtime_get_sync(pd->dev); + clk_prepare_enable(pd->clk); /* Process all messages */ for (i = 0; i < num; i++) { @@ -754,7 +739,12 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, break; } - deactivate_ch(pd); + /* Disable channel */ + iic_set_clr(pd, ICCR, 0, ICCR_ICE); + + /* Disable clock and mark device as idle */ + clk_disable_unprepare(pd->clk); + pm_runtime_put_sync(pd->dev); if (!err) err = num; -- cgit From 832a522a3ef5e96b517163ee7d4c249545d88626 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:30 +0100 Subject: i2c: sh_mobile: use direct writes when accessing ICE bit ICE bit is for resetting the module. Other bits don't matter then, so we don't need to use the iic_set_clr() function but can use iic_wr(). Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 02c2912bebb4..72c9483db769 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -620,10 +620,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, if (do_init) { /* Initialize channel registers */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); + iic_wr(pd, ICCR, 0); /* Enable channel and configure rx ack */ - iic_set_clr(pd, ICCR, ICCR_ICE, 0); + iic_wr(pd, ICCR, ICCR_ICE); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl & 0xff); @@ -740,7 +740,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, } /* Disable channel */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); + iic_wr(pd, ICCR, 0); /* Disable clock and mark device as idle */ clk_disable_unprepare(pd->clk); -- cgit From a4d16493be406273320f152814c33ccdb17dcf91 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:31 +0100 Subject: i2c: sh_mobile: shorten exit of xfer routine We can use the ternary operator for easier reading. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 72c9483db769..ebd146ccb244 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -746,9 +746,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, clk_disable_unprepare(pd->clk); pm_runtime_put_sync(pd->dev); - if (!err) - err = num; - return err; + return err ?: num; } static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) -- cgit From 91701ae85dff9703335b5912673df75f4b6f4c53 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Nov 2017 09:50:37 +0100 Subject: i2c: sh_mobile: let RuntimePM do the clock handling No need to do it manually. Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index ebd146ccb244..80561ffbcf7b 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -702,7 +702,6 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, /* Wake up device and enable clock */ pm_runtime_get_sync(pd->dev); - clk_prepare_enable(pd->clk); /* Process all messages */ for (i = 0; i < num; i++) { @@ -743,7 +742,6 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, iic_wr(pd, ICCR, 0); /* Disable clock and mark device as idle */ - clk_disable_unprepare(pd->clk); pm_runtime_put_sync(pd->dev); return err ?: num; -- cgit From 2967f9ca8b0dc8d924e0f14c55d1e73d9c6c4975 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 9 Nov 2017 23:20:53 +0100 Subject: i2c: sh_mobile: avoid unnecessary register read There is no data when the first WAIT interrupt arrives. No need to read something then. Signed-off-by: Wolfram Sang Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 80561ffbcf7b..40a66d466c3c 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -433,8 +433,9 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) break; } data = i2c_op(pd, OP_RX_STOP_DATA, 0); - } else + } else if (real_pos >= 0) { data = i2c_op(pd, OP_RX, 0); + } if (real_pos >= 0) pd->msg->buf[real_pos] = data; -- cgit From a4fde7e5c9d6432ba863ee53debf27f10b370678 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 10 Nov 2017 12:52:10 +0100 Subject: i2c: sh_mobile: send STOP according to datasheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We initiate STOP (or REP_START) on the second last WAIT interrupt currently. This works fine but is not according to the datasheet which says to do it on the last WAIT interrupt. This also simplifies the code quite a lot, so let's do it. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 40a66d466c3c..c904be631db3 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -40,21 +40,21 @@ /* BUS: S A8 ACK P(*) */ /* IRQ: DTE WAIT */ /* ICIC: */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 */ /* */ /* 1 byte transmit */ /* BUS: S A8 ACK D8(1) ACK P(*) */ /* IRQ: DTE WAIT WAIT */ /* ICIC: -DTE */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 D8(1) */ /* */ /* 2 byte transmit */ /* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */ /* IRQ: DTE WAIT WAIT WAIT */ /* ICIC: -DTE */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 D8(1) D8(2) */ /* */ /* 3 bytes or more, +---------+ gets repeated */ @@ -113,7 +113,6 @@ enum sh_mobile_i2c_op { OP_TX_FIRST, OP_TX, OP_TX_STOP, - OP_TX_STOP_DATA, OP_TX_TO_RX, OP_RX, OP_RX_STOP, @@ -319,10 +318,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, case OP_TX: /* write data */ iic_wr(pd, ICDR, data); break; - case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */ - iic_wr(pd, ICDR, data); - /* fallthrough */ - case OP_TX_STOP: /* issue a stop */ + case OP_TX_STOP: /* issue a stop (or rep_start) */ iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS : ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; @@ -356,11 +352,6 @@ static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd) return pd->pos == -1; } -static bool sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd) -{ - return pd->pos == pd->msg->len - 1; -} - static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd, unsigned char *buf) { @@ -378,20 +369,12 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) unsigned char data; if (pd->pos == pd->msg->len) { - /* Send stop if we haven't yet (DMA case) */ - if (pd->send_stop && pd->stop_after_dma) - i2c_op(pd, OP_TX_STOP, 0); + i2c_op(pd, OP_TX_STOP, 0); return 1; } sh_mobile_i2c_get_data(pd, &data); - - if (sh_mobile_i2c_is_last_byte(pd)) - i2c_op(pd, OP_TX_STOP_DATA, data); - else if (sh_mobile_i2c_is_first_byte(pd)) - i2c_op(pd, OP_TX_FIRST, data); - else - i2c_op(pd, OP_TX, data); + i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, data); pd->pos++; return 0; -- cgit From 4ed152c4daf32d2cd4a5285f3aaca3a4c89a31fb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 15 Nov 2017 15:32:21 +0100 Subject: i2c: sh_mobile: make sure to not accidently trigger STOP The datasheet was a bit vague, but after consultation with HW designers, we came to the conclusion that we should set the SCP bit always when dealing only with the ICE bit. A set SCP bit is ignored, and thus fine, a cleared one may trigger STOP on the bus. Signed-off-by: Wolfram Sang Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index c904be631db3..bc1605a31534 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -604,10 +604,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, if (do_init) { /* Initialize channel registers */ - iic_wr(pd, ICCR, 0); + iic_wr(pd, ICCR, ICCR_SCP); /* Enable channel and configure rx ack */ - iic_wr(pd, ICCR, ICCR_ICE); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl & 0xff); @@ -723,7 +723,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, } /* Disable channel */ - iic_wr(pd, ICCR, 0); + iic_wr(pd, ICCR, ICCR_SCP); /* Disable clock and mark device as idle */ pm_runtime_put_sync(pd->dev); -- cgit From 3f35221842305e82494e10fcfc1f5750c8bc682a Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 7 Nov 2017 15:10:43 +0000 Subject: pinctrl: sh-pfc: r8a7745: Add CAN[01] support This patch adds PFC CAN0 and CAN1 pin groups and functions, enabling CAN bus on the RZ/G1E. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7794.c | 146 +++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index 333a3470e842..e5b3d5fa4aa0 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -1608,6 +1608,116 @@ static const unsigned int avb_gmii_mux[] = { AVB_TX_EN_MARK, AVB_TX_ER_MARK, AVB_TX_CLK_MARK, AVB_COL_MARK, }; + +/* - CAN -------------------------------------------------------------------- */ +static const unsigned int can0_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(6, 15), RCAR_GP_PIN(6, 14), +}; + +static const unsigned int can0_data_mux[] = { + CAN0_TX_MARK, CAN0_RX_MARK, +}; + +static const unsigned int can0_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(3, 16), RCAR_GP_PIN(3, 15), +}; + +static const unsigned int can0_data_b_mux[] = { + CAN0_TX_B_MARK, CAN0_RX_B_MARK, +}; + +static const unsigned int can0_data_c_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(2, 17), RCAR_GP_PIN(2, 16), +}; + +static const unsigned int can0_data_c_mux[] = { + CAN0_TX_C_MARK, CAN0_RX_C_MARK, +}; + +static const unsigned int can0_data_d_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 11), +}; + +static const unsigned int can0_data_d_mux[] = { + CAN0_TX_D_MARK, CAN0_RX_D_MARK, +}; + +static const unsigned int can1_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(6, 25), RCAR_GP_PIN(6, 24), +}; + +static const unsigned int can1_data_mux[] = { + CAN1_TX_MARK, CAN1_RX_MARK, +}; + +static const unsigned int can1_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 1), +}; + +static const unsigned int can1_data_b_mux[] = { + CAN1_TX_B_MARK, CAN1_RX_B_MARK, +}; + +static const unsigned int can1_data_c_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 5), +}; + +static const unsigned int can1_data_c_mux[] = { + CAN1_TX_C_MARK, CAN1_RX_C_MARK, +}; + +static const unsigned int can1_data_d_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(3, 31), RCAR_GP_PIN(3, 30), +}; + +static const unsigned int can1_data_d_mux[] = { + CAN1_TX_D_MARK, CAN1_RX_D_MARK, +}; + +static const unsigned int can_clk_pins[] = { + /* CLK */ + RCAR_GP_PIN(3, 31), +}; + +static const unsigned int can_clk_mux[] = { + CAN_CLK_MARK, +}; + +static const unsigned int can_clk_b_pins[] = { + /* CLK */ + RCAR_GP_PIN(1, 23), +}; + +static const unsigned int can_clk_b_mux[] = { + CAN_CLK_B_MARK, +}; + +static const unsigned int can_clk_c_pins[] = { + /* CLK */ + RCAR_GP_PIN(1, 0), +}; + +static const unsigned int can_clk_c_mux[] = { + CAN_CLK_C_MARK, +}; + +static const unsigned int can_clk_d_pins[] = { + /* CLK */ + RCAR_GP_PIN(5, 0), +}; + +static const unsigned int can_clk_d_mux[] = { + CAN_CLK_D_MARK, +}; + /* - DU --------------------------------------------------------------------- */ static const unsigned int du0_rgb666_pins[] = { /* R[7:2], G[7:2], B[7:2] */ @@ -3459,6 +3569,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb_mdio), SH_PFC_PIN_GROUP(avb_mii), SH_PFC_PIN_GROUP(avb_gmii), + SH_PFC_PIN_GROUP(can0_data), + SH_PFC_PIN_GROUP(can0_data_b), + SH_PFC_PIN_GROUP(can0_data_c), + SH_PFC_PIN_GROUP(can0_data_d), + SH_PFC_PIN_GROUP(can1_data), + SH_PFC_PIN_GROUP(can1_data_b), + SH_PFC_PIN_GROUP(can1_data_c), + SH_PFC_PIN_GROUP(can1_data_d), + SH_PFC_PIN_GROUP(can_clk), + SH_PFC_PIN_GROUP(can_clk_b), + SH_PFC_PIN_GROUP(can_clk_c), + SH_PFC_PIN_GROUP(can_clk_d), SH_PFC_PIN_GROUP(du0_rgb666), SH_PFC_PIN_GROUP(du0_rgb888), SH_PFC_PIN_GROUP(du0_clk0_out), @@ -3731,6 +3853,28 @@ static const char * const avb_groups[] = { "avb_gmii", }; +static const char * const can0_groups[] = { + "can0_data", + "can0_data_b", + "can0_data_c", + "can0_data_d", + "can_clk", + "can_clk_b", + "can_clk_c", + "can_clk_d", +}; + +static const char * const can1_groups[] = { + "can1_data", + "can1_data_b", + "can1_data_c", + "can1_data_d", + "can_clk", + "can_clk_b", + "can_clk_c", + "can_clk_d", +}; + static const char * const du0_groups[] = { "du0_rgb666", "du0_rgb888", @@ -4102,6 +4246,8 @@ static const char * const vin1_groups[] = { static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(audio_clk), SH_PFC_FUNCTION(avb), + SH_PFC_FUNCTION(can0), + SH_PFC_FUNCTION(can1), SH_PFC_FUNCTION(du0), SH_PFC_FUNCTION(du1), SH_PFC_FUNCTION(eth), -- cgit From a678abfee7ab5d2dcfc2079158ec799c7f4cf204 Mon Sep 17 00:00:00 2001 From: Ramesh Shanmugasundaram Date: Fri, 10 Nov 2017 13:58:49 +0000 Subject: pinctrl: sh-pfc: r8a7795: Add CAN support This patch adds CAN[0-1] pinmux support for R-Car H3 ES2.0. The pin config is identical to H3 ES1.*. Signed-off-by: Ramesh Shanmugasundaram Reviewed-by: Fabrizio Castro Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795.c | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index d1cec6d12e81..59249a990cef 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -1781,6 +1781,38 @@ static const unsigned int avb_avtp_capture_b_mux[] = { AVB_AVTP_CAPTURE_B_MARK, }; +/* - CAN ------------------------------------------------------------------ */ +static const unsigned int can0_data_a_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), +}; +static const unsigned int can0_data_a_mux[] = { + CAN0_TX_A_MARK, CAN0_RX_A_MARK, +}; +static const unsigned int can0_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), +}; +static const unsigned int can0_data_b_mux[] = { + CAN0_TX_B_MARK, CAN0_RX_B_MARK, +}; +static const unsigned int can1_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26), +}; +static const unsigned int can1_data_mux[] = { + CAN1_TX_MARK, CAN1_RX_MARK, +}; + +/* - CAN Clock -------------------------------------------------------------- */ +static const unsigned int can_clk_pins[] = { + /* CLK */ + RCAR_GP_PIN(1, 25), +}; +static const unsigned int can_clk_mux[] = { + CAN_CLK_MARK, +}; + /* - DRIF0 --------------------------------------------------------------- */ static const unsigned int drif0_ctrl_a_pins[] = { /* CLK, SYNC */ @@ -3843,6 +3875,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb_avtp_capture_a), SH_PFC_PIN_GROUP(avb_avtp_match_b), SH_PFC_PIN_GROUP(avb_avtp_capture_b), + SH_PFC_PIN_GROUP(can0_data_a), + SH_PFC_PIN_GROUP(can0_data_b), + SH_PFC_PIN_GROUP(can1_data), + SH_PFC_PIN_GROUP(can_clk), SH_PFC_PIN_GROUP(drif0_ctrl_a), SH_PFC_PIN_GROUP(drif0_data0_a), SH_PFC_PIN_GROUP(drif0_data1_a), @@ -4154,6 +4190,19 @@ static const char * const avb_groups[] = { "avb_avtp_capture_b", }; +static const char * const can0_groups[] = { + "can0_data_a", + "can0_data_b", +}; + +static const char * const can1_groups[] = { + "can1_data", +}; + +static const char * const can_clk_groups[] = { + "can_clk", +}; + static const char * const drif0_groups[] = { "drif0_ctrl_a", "drif0_data0_a", @@ -4559,6 +4608,9 @@ static const char * const usb30_groups[] = { static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(audio_clk), SH_PFC_FUNCTION(avb), + SH_PFC_FUNCTION(can0), + SH_PFC_FUNCTION(can1), + SH_PFC_FUNCTION(can_clk), SH_PFC_FUNCTION(drif0), SH_PFC_FUNCTION(drif1), SH_PFC_FUNCTION(drif2), -- cgit From 0e1c7a94c6def25fa2458ad4577b0b9b40443c3b Mon Sep 17 00:00:00 2001 From: Ramesh Shanmugasundaram Date: Fri, 10 Nov 2017 13:58:50 +0000 Subject: pinctrl: sh-pfc: r8a7795: Add CAN FD support This patch adds CAN FD[0-1] pinmux support for R-Car H3 ES2.0. The pin config is identical to H3 ES1.*. Signed-off-by: Ramesh Shanmugasundaram Reviewed-by: Fabrizio Castro Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795.c | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index 59249a990cef..34a2dc471e5a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -1813,6 +1813,29 @@ static const unsigned int can_clk_mux[] = { CAN_CLK_MARK, }; +/* - CAN FD --------------------------------------------------------------- */ +static const unsigned int canfd0_data_a_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), +}; +static const unsigned int canfd0_data_a_mux[] = { + CANFD0_TX_A_MARK, CANFD0_RX_A_MARK, +}; +static const unsigned int canfd0_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), +}; +static const unsigned int canfd0_data_b_mux[] = { + CANFD0_TX_B_MARK, CANFD0_RX_B_MARK, +}; +static const unsigned int canfd1_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26), +}; +static const unsigned int canfd1_data_mux[] = { + CANFD1_TX_MARK, CANFD1_RX_MARK, +}; + /* - DRIF0 --------------------------------------------------------------- */ static const unsigned int drif0_ctrl_a_pins[] = { /* CLK, SYNC */ @@ -3879,6 +3902,9 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(can0_data_b), SH_PFC_PIN_GROUP(can1_data), SH_PFC_PIN_GROUP(can_clk), + SH_PFC_PIN_GROUP(canfd0_data_a), + SH_PFC_PIN_GROUP(canfd0_data_b), + SH_PFC_PIN_GROUP(canfd1_data), SH_PFC_PIN_GROUP(drif0_ctrl_a), SH_PFC_PIN_GROUP(drif0_data0_a), SH_PFC_PIN_GROUP(drif0_data1_a), @@ -4203,6 +4229,15 @@ static const char * const can_clk_groups[] = { "can_clk", }; +static const char * const canfd0_groups[] = { + "canfd0_data_a", + "canfd0_data_b", +}; + +static const char * const canfd1_groups[] = { + "canfd1_data", +}; + static const char * const drif0_groups[] = { "drif0_ctrl_a", "drif0_data0_a", @@ -4611,6 +4646,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(can0), SH_PFC_FUNCTION(can1), SH_PFC_FUNCTION(can_clk), + SH_PFC_FUNCTION(canfd0), + SH_PFC_FUNCTION(canfd1), SH_PFC_FUNCTION(drif0), SH_PFC_FUNCTION(drif1), SH_PFC_FUNCTION(drif2), -- cgit From 5a0e698876479b71de885fdc181c00ecee5a61a9 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 10 Nov 2017 20:59:00 +0300 Subject: pinctrl: sh-pfc: Add PORT_GP_CFG_{6|22}() helper macros They follow the style of the existing PORT_GP_CFG_() macros and will be used by a follow-up patch for the R8A77970 SoC. Based on the original (and large) patch by Daisuke Matsushita . Signed-off-by: Vladimir Barinov Signed-off-by: Sergei Shtylyov Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/sh_pfc.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h index 213108a058fe..efe07bcca8d0 100644 --- a/drivers/pinctrl/sh-pfc/sh_pfc.h +++ b/drivers/pinctrl/sh-pfc/sh_pfc.h @@ -389,10 +389,14 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; PORT_GP_CFG_1(bank, 3, fn, sfx, cfg) #define PORT_GP_4(bank, fn, sfx) PORT_GP_CFG_4(bank, fn, sfx, 0) -#define PORT_GP_CFG_8(bank, fn, sfx, cfg) \ +#define PORT_GP_CFG_6(bank, fn, sfx, cfg) \ PORT_GP_CFG_4(bank, fn, sfx, cfg), \ PORT_GP_CFG_1(bank, 4, fn, sfx, cfg), \ - PORT_GP_CFG_1(bank, 5, fn, sfx, cfg), \ + PORT_GP_CFG_1(bank, 5, fn, sfx, cfg) +#define PORT_GP_6(bank, fn, sfx) PORT_GP_CFG_6(bank, fn, sfx, 0) + +#define PORT_GP_CFG_8(bank, fn, sfx, cfg) \ + PORT_GP_CFG_6(bank, fn, sfx, cfg), \ PORT_GP_CFG_1(bank, 6, fn, sfx, cfg), \ PORT_GP_CFG_1(bank, 7, fn, sfx, cfg) #define PORT_GP_8(bank, fn, sfx) PORT_GP_CFG_8(bank, fn, sfx, 0) @@ -450,9 +454,13 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; PORT_GP_CFG_1(bank, 20, fn, sfx, cfg) #define PORT_GP_21(bank, fn, sfx) PORT_GP_CFG_21(bank, fn, sfx, 0) -#define PORT_GP_CFG_23(bank, fn, sfx, cfg) \ +#define PORT_GP_CFG_22(bank, fn, sfx, cfg) \ PORT_GP_CFG_21(bank, fn, sfx, cfg), \ - PORT_GP_CFG_1(bank, 21, fn, sfx, cfg), \ + PORT_GP_CFG_1(bank, 21, fn, sfx, cfg) +#define PORT_GP_22(bank, fn, sfx) PORT_GP_CFG_22(bank, fn, sfx, 0) + +#define PORT_GP_CFG_23(bank, fn, sfx, cfg) \ + PORT_GP_CFG_22(bank, fn, sfx, cfg), \ PORT_GP_CFG_1(bank, 22, fn, sfx, cfg) #define PORT_GP_23(bank, fn, sfx) PORT_GP_CFG_23(bank, fn, sfx, 0) -- cgit From 10c9ef045a7e19e9fd4c829c7321f9d2048808c0 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 28 Nov 2017 11:09:10 +0800 Subject: i2c: core: fix compile issue related to incorrect gpio header The correct header to include for the gpiod interface is . Fixes: 3991c5c80beaf7eb9 ("i2c: Switch to using gpiod interface for gpio bus recovery") Signed-off-by: Phil Reid Reviewed-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 54ffc8da40df..bf52cca87363 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include -- cgit From 4d67c2e7f60dbf5a3cf65f6773c73e12970b0fe0 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 28 Nov 2017 11:09:11 +0800 Subject: i2c: designware: fix building driver as module The designware core and platform are built as separate modules. Export i2c_dw_prepare_clk() so it can be used by the platform driver. Fixes: a34a0b6da22540d19e57 ("i2c: designware: move i2c_dw_plat_prepare_clk to common") Signed-off-by: Phil Reid Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 6b82809647dc..27ebd90de43b 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -197,6 +197,7 @@ int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare) clk_disable_unprepare(dev->clk); return 0; } +EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) { -- cgit From dabd4bc6de2bd33f705e840f4aba6c836df9af21 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Nov 2017 21:39:28 +0200 Subject: pinctrl: intel: merrifield: Introduce ACPI device table On Intel Merrifield the pin control device is a separate IP block without any PCI ID assigned. Though, recently we got an allocated ACPI ID for it, so, let's use fresh ID. Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-merrifield.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c index 86c4b3fab7b0..d9357054d41d 100644 --- a/drivers/pinctrl/intel/pinctrl-merrifield.c +++ b/drivers/pinctrl/intel/pinctrl-merrifield.c @@ -931,10 +931,17 @@ static int mrfld_pinctrl_probe(struct platform_device *pdev) return 0; } +static const struct acpi_device_id mrfld_acpi_table[] = { + { "INTC1002" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, mrfld_acpi_table); + static struct platform_driver mrfld_pinctrl_driver = { .probe = mrfld_pinctrl_probe, .driver = { .name = "pinctrl-merrifield", + .acpi_match_table = mrfld_acpi_table, }, }; -- cgit From 03c4749dd6c7ff948a0ce59a44a1b97c015353c2 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 27 Nov 2017 16:54:42 +0300 Subject: gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation We added acpi_gpiochip_pin_to_gpio_offset() because there was a need to translate from ACPI GpioIo/GpioInt number to Linux GPIO number in the Cherryview pinctrl driver. This translation is necessary because Cherryview has gaps in the pin list and the driver used continuous GPIO number space in Linux side as follows: created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 8->19 ==> INT33FF:03 PIN 15->26 created GPIO range 20->25 ==> INT33FF:03 PIN 30->35 created GPIO range 26->33 ==> INT33FF:03 PIN 45->52 created GPIO range 34->43 ==> INT33FF:03 PIN 60->69 created GPIO range 44->54 ==> INT33FF:03 PIN 75->85 For example when ACPI GpioInt resource refers to GPIO 81 (SDMMC3_CD_B) we translate from pin 81 to the corresponding Linux GPIO number, which is 50. This number is then used when the GPIO is accessed through gpiolib. It turns out, this is not necessary at all. We can just pass 1:1 mapping between Linux GPIO numbers and pin numbers (including gaps) and the pinctrl core handles all the details automatically: created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 15->26 ==> INT33FF:03 PIN 15->26 created GPIO range 30->35 ==> INT33FF:03 PIN 30->35 created GPIO range 45->52 ==> INT33FF:03 PIN 45->52 created GPIO range 60->69 ==> INT33FF:03 PIN 60->69 created GPIO range 75->85 ==> INT33FF:03 PIN 75->85 Here GPIO 81 is exactly same than the hardware pin 81 (SDMMC3_CD_B). As an added bonus this simplifies both the ACPI GPIO core code and the Cherryview pinctrl driver. Signed-off-by: Mika Westerberg Acked-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 75 +----------------------------- drivers/pinctrl/intel/pinctrl-cherryview.c | 59 ++++++++--------------- 2 files changed, 22 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index eb4528c87c0b..b77c544bf7e2 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -58,58 +58,6 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) return ACPI_HANDLE(gc->parent) == data; } -#ifdef CONFIG_PINCTRL -/** - * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO - * @gdev: GPIO device - * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource - * - * Function takes ACPI GpioIo/GpioInt pin number as a parameter and - * translates it to a corresponding offset suitable to be passed to a - * GPIO controller driver. - * - * Typically the returned offset is same as @pin, but if the GPIO - * controller uses pin controller and the mapping is not contiguous the - * offset might be different. - */ -static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_device *gdev, int pin) -{ - struct gpio_pin_range *pin_range; - - /* If there are no ranges in this chip, use 1:1 mapping */ - if (list_empty(&gdev->pin_ranges)) - return pin; - - list_for_each_entry(pin_range, &gdev->pin_ranges, node) { - const struct pinctrl_gpio_range *range = &pin_range->range; - int i; - - if (range->pins) { - for (i = 0; i < range->npins; i++) { - if (range->pins[i] == pin) - return range->base + i - gdev->base; - } - } else { - if (pin >= range->pin_base && - pin < range->pin_base + range->npins) { - unsigned gpio_base; - - gpio_base = range->base - gdev->base; - return gpio_base + pin - range->pin_base; - } - } - } - - return -EINVAL; -} -#else -static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_device *gdev, - int pin) -{ - return pin; -} -#endif - /** * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") @@ -125,7 +73,6 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) struct gpio_chip *chip; acpi_handle handle; acpi_status status; - int offset; status = acpi_get_handle(NULL, path, &handle); if (ACPI_FAILURE(status)) @@ -135,11 +82,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) if (!chip) return ERR_PTR(-EPROBE_DEFER); - offset = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin); - if (offset < 0) - return ERR_PTR(offset); - - return gpiochip_get_desc(chip, offset); + return gpiochip_get_desc(chip, pin); } static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) @@ -216,10 +159,6 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, if (!handler) return AE_OK; - pin = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin); - if (pin < 0) - return AE_BAD_PARAMETER; - desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event"); if (IS_ERR(desc)) { dev_err(chip->parent, "Failed to request GPIO\n"); @@ -852,12 +791,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, struct gpio_desc *desc; bool found; - pin = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin); - if (pin < 0) { - status = AE_BAD_PARAMETER; - goto out; - } - mutex_lock(&achip->conn_lock); found = false; @@ -990,11 +923,7 @@ static struct gpio_desc *acpi_gpiochip_parse_own_gpio( if (ret < 0) return ERR_PTR(ret); - ret = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, gpios[0]); - if (ret < 0) - return ERR_PTR(ret); - - desc = gpiochip_get_desc(chip, ret); + desc = gpiochip_get_desc(chip, gpios[0]); if (IS_ERR(desc)) return desc; diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index bdedb6325c72..aa6c9f569c2b 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -131,10 +131,8 @@ struct chv_gpio_pinrange { * @ngroups: Number of groups * @functions: All functions in this community * @nfunctions: Number of functions - * @ngpios: Number of GPIOs in this community * @gpio_ranges: An array of GPIO ranges in this community * @ngpio_ranges: Number of GPIO ranges - * @ngpios: Total number of GPIOs in this community * @nirqs: Total number of IRQs this community can generate */ struct chv_community { @@ -147,7 +145,6 @@ struct chv_community { size_t nfunctions; const struct chv_gpio_pinrange *gpio_ranges; size_t ngpio_ranges; - size_t ngpios; size_t nirqs; acpi_adr_space_type acpi_space_id; }; @@ -399,7 +396,6 @@ static const struct chv_community southwest_community = { .nfunctions = ARRAY_SIZE(southwest_functions), .gpio_ranges = southwest_gpio_ranges, .ngpio_ranges = ARRAY_SIZE(southwest_gpio_ranges), - .ngpios = ARRAY_SIZE(southwest_pins), /* * Southwest community can benerate GPIO interrupts only for the * first 8 interrupts. The upper half (8-15) can only be used to @@ -489,7 +485,6 @@ static const struct chv_community north_community = { .npins = ARRAY_SIZE(north_pins), .gpio_ranges = north_gpio_ranges, .ngpio_ranges = ARRAY_SIZE(north_gpio_ranges), - .ngpios = ARRAY_SIZE(north_pins), /* * North community can generate GPIO interrupts only for the first * 8 interrupts. The upper half (8-15) can only be used to trigger @@ -538,7 +533,6 @@ static const struct chv_community east_community = { .npins = ARRAY_SIZE(east_pins), .gpio_ranges = east_gpio_ranges, .ngpio_ranges = ARRAY_SIZE(east_gpio_ranges), - .ngpios = ARRAY_SIZE(east_pins), .nirqs = 16, .acpi_space_id = 0x93, }; @@ -665,7 +659,6 @@ static const struct chv_community southeast_community = { .nfunctions = ARRAY_SIZE(southeast_functions), .gpio_ranges = southeast_gpio_ranges, .ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges), - .ngpios = ARRAY_SIZE(southeast_pins), .nirqs = 16, .acpi_space_id = 0x94, }; @@ -1253,21 +1246,14 @@ static struct pinctrl_desc chv_pinctrl_desc = { .owner = THIS_MODULE, }; -static unsigned chv_gpio_offset_to_pin(struct chv_pinctrl *pctrl, - unsigned offset) -{ - return pctrl->community->pins[offset].number; -} - static int chv_gpio_get(struct gpio_chip *chip, unsigned offset) { struct chv_pinctrl *pctrl = gpiochip_get_data(chip); - int pin = chv_gpio_offset_to_pin(pctrl, offset); unsigned long flags; u32 ctrl0, cfg; raw_spin_lock_irqsave(&chv_lock, flags); - ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); raw_spin_unlock_irqrestore(&chv_lock, flags); cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; @@ -1281,14 +1267,13 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset) static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct chv_pinctrl *pctrl = gpiochip_get_data(chip); - unsigned pin = chv_gpio_offset_to_pin(pctrl, offset); unsigned long flags; void __iomem *reg; u32 ctrl0; raw_spin_lock_irqsave(&chv_lock, flags); - reg = chv_padreg(pctrl, pin, CHV_PADCTRL0); + reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); ctrl0 = readl(reg); if (value) @@ -1304,12 +1289,11 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct chv_pinctrl *pctrl = gpiochip_get_data(chip); - unsigned pin = chv_gpio_offset_to_pin(pctrl, offset); u32 ctrl0, direction; unsigned long flags; raw_spin_lock_irqsave(&chv_lock, flags); - ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); raw_spin_unlock_irqrestore(&chv_lock, flags); direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; @@ -1345,7 +1329,7 @@ static void chv_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct chv_pinctrl *pctrl = gpiochip_get_data(gc); - int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d)); + int pin = irqd_to_hwirq(d); u32 intr_line; raw_spin_lock(&chv_lock); @@ -1362,7 +1346,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct chv_pinctrl *pctrl = gpiochip_get_data(gc); - int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d)); + int pin = irqd_to_hwirq(d); u32 value, intr_line; unsigned long flags; @@ -1407,8 +1391,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct chv_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned offset = irqd_to_hwirq(d); - int pin = chv_gpio_offset_to_pin(pctrl, offset); + unsigned pin = irqd_to_hwirq(d); irq_flow_handler_t handler; unsigned long flags; u32 intsel, value; @@ -1426,7 +1409,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) if (!pctrl->intr_lines[intsel]) { irq_set_handler_locked(d, handler); - pctrl->intr_lines[intsel] = offset; + pctrl->intr_lines[intsel] = pin; } raw_spin_unlock_irqrestore(&chv_lock, flags); } @@ -1439,8 +1422,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct chv_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned offset = irqd_to_hwirq(d); - int pin = chv_gpio_offset_to_pin(pctrl, offset); + unsigned pin = irqd_to_hwirq(d); unsigned long flags; u32 value; @@ -1486,7 +1468,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) value &= CHV_PADCTRL0_INTSEL_MASK; value >>= CHV_PADCTRL0_INTSEL_SHIFT; - pctrl->intr_lines[value] = offset; + pctrl->intr_lines[value] = pin; if (type & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(d, handle_edge_irq); @@ -1576,12 +1558,12 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) const struct chv_gpio_pinrange *range; struct gpio_chip *chip = &pctrl->chip; bool need_valid_mask = !dmi_check_system(chv_no_valid_mask); - int ret, i, offset; - int irq_base; + const struct chv_community *community = pctrl->community; + int ret, i, irq_base; *chip = chv_gpio_chip; - chip->ngpio = pctrl->community->ngpios; + chip->ngpio = community->pins[community->npins - 1].number + 1; chip->label = dev_name(pctrl->dev); chip->parent = pctrl->dev; chip->base = -1; @@ -1593,30 +1575,29 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) return ret; } - for (i = 0, offset = 0; i < pctrl->community->ngpio_ranges; i++) { - range = &pctrl->community->gpio_ranges[i]; - ret = gpiochip_add_pin_range(chip, dev_name(pctrl->dev), offset, - range->base, range->npins); + for (i = 0; i < community->ngpio_ranges; i++) { + range = &community->gpio_ranges[i]; + ret = gpiochip_add_pin_range(chip, dev_name(pctrl->dev), + range->base, range->base, + range->npins); if (ret) { dev_err(pctrl->dev, "failed to add GPIO pin range\n"); return ret; } - - offset += range->npins; } /* Do not add GPIOs that can only generate GPEs to the IRQ domain */ - for (i = 0; i < pctrl->community->npins; i++) { + for (i = 0; i < community->npins; i++) { const struct pinctrl_pin_desc *desc; u32 intsel; - desc = &pctrl->community->pins[i]; + desc = &community->pins[i]; intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0)); intsel &= CHV_PADCTRL0_INTSEL_MASK; intsel >>= CHV_PADCTRL0_INTSEL_SHIFT; - if (need_valid_mask && intsel >= pctrl->community->nirqs) + if (need_valid_mask && intsel >= community->nirqs) clear_bit(i, chip->irq.valid_mask); } -- cgit From a60eac3239f01838bdd34eaac8c486c4c6e84551 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 27 Nov 2017 16:54:43 +0300 Subject: pinctrl: intel: Allow custom GPIO base for pad groups Currently we always have direct mapping between GPIO numbers and the hardware pin numbers. However, there are cases where that's not the case anymore (more about this in the next patch). Instead we need to be able to specify custom GPIO base for certain pad groups. To support this, add a new field (gpio_base) to the pad group structure and update the core Intel pinctrl driver to handle this accordingly. Passing 0 as gpio_base will use direct mapping so the existing drivers do not need to be modified. Passing -1 excludes the whole pad group from having GPIO mapping. Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-intel.c | 156 +++++++++++++++++++++++++--------- drivers/pinctrl/intel/pinctrl-intel.h | 3 + 2 files changed, 120 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 12a1af45acb9..4c2369a8d926 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -806,22 +806,63 @@ static const struct gpio_chip intel_gpio_chip = { .set_config = gpiochip_generic_config, }; +/** + * intel_gpio_to_pin() - Translate from GPIO offset to pin number + * @pctrl: Pinctrl structure + * @offset: GPIO offset from gpiolib + * @commmunity: Community is filled here if not %NULL + * @padgrp: Pad group is filled here if not %NULL + * + * When coming through gpiolib irqchip, the GPIO offset is not + * automatically translated to pinctrl pin number. This function can be + * used to find out the corresponding pinctrl pin. + */ +static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset, + const struct intel_community **community, + const struct intel_padgroup **padgrp) +{ + int i; + + for (i = 0; i < pctrl->ncommunities; i++) { + const struct intel_community *comm = &pctrl->communities[i]; + int j; + + for (j = 0; j < comm->ngpps; j++) { + const struct intel_padgroup *pgrp = &comm->gpps[j]; + + if (pgrp->gpio_base < 0) + continue; + + if (offset >= pgrp->gpio_base && + offset < pgrp->gpio_base + pgrp->size) { + int pin; + + pin = pgrp->base + offset - pgrp->gpio_base; + if (community) + *community = comm; + if (padgrp) + *padgrp = pgrp; + + return pin; + } + } + } + + return -EINVAL; +} + static void intel_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); const struct intel_community *community; - unsigned pin = irqd_to_hwirq(d); + const struct intel_padgroup *padgrp; + int pin; - community = intel_get_community(pctrl, pin); - if (community) { - const struct intel_padgroup *padgrp; + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { unsigned gpp, gpp_offset, is_offset; - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return; - gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); is_offset = community->is_offset + gpp * 4; @@ -837,19 +878,15 @@ static void intel_gpio_irq_enable(struct irq_data *d) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); const struct intel_community *community; - unsigned pin = irqd_to_hwirq(d); + const struct intel_padgroup *padgrp; + int pin; - community = intel_get_community(pctrl, pin); - if (community) { - const struct intel_padgroup *padgrp; + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { unsigned gpp, gpp_offset, is_offset; unsigned long flags; u32 value; - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return; - gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); is_offset = community->is_offset + gpp * 4; @@ -870,20 +907,16 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); const struct intel_community *community; - unsigned pin = irqd_to_hwirq(d); + const struct intel_padgroup *padgrp; + int pin; - community = intel_get_community(pctrl, pin); - if (community) { - const struct intel_padgroup *padgrp; + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { unsigned gpp, gpp_offset; unsigned long flags; void __iomem *reg; u32 value; - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return; - gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); @@ -914,7 +947,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = irqd_to_hwirq(d); + unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); unsigned long flags; void __iomem *reg; u32 value; @@ -969,7 +1002,7 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = irqd_to_hwirq(d); + unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); if (on) enable_irq_wake(pctrl->irq); @@ -1000,14 +1033,10 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, pending &= enabled; for_each_set_bit(gpp_offset, &pending, padgrp->size) { - unsigned padno, irq; - - padno = padgrp->base - community->pin_base + gpp_offset; - if (padno >= community->npins) - break; + unsigned irq; irq = irq_find_mapping(gc->irq.domain, - community->pin_base + padno); + padgrp->gpio_base + gpp_offset); generic_handle_irq(irq); ret |= IRQ_HANDLED; @@ -1044,13 +1073,56 @@ static struct irq_chip intel_gpio_irqchip = { .flags = IRQCHIP_MASK_ON_SUSPEND, }; +static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl, + const struct intel_community *community) +{ + int ret, i; + + for (i = 0; i < community->ngpps; i++) { + const struct intel_padgroup *gpp = &community->gpps[i]; + + if (gpp->gpio_base < 0) + continue; + + ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), + gpp->gpio_base, gpp->base, + gpp->size); + if (ret) + return ret; + } + + return ret; +} + +static unsigned intel_gpio_ngpio(const struct intel_pinctrl *pctrl) +{ + const struct intel_community *community; + unsigned ngpio = 0; + int i, j; + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + for (j = 0; j < community->ngpps; j++) { + const struct intel_padgroup *gpp = &community->gpps[j]; + + if (gpp->gpio_base < 0) + continue; + + if (gpp->gpio_base + gpp->size > ngpio) + ngpio = gpp->gpio_base + gpp->size; + } + } + + return ngpio; +} + static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) { - int ret; + int ret, i; pctrl->chip = intel_gpio_chip; - pctrl->chip.ngpio = pctrl->soc->npins; + pctrl->chip.ngpio = intel_gpio_ngpio(pctrl); pctrl->chip.label = dev_name(pctrl->dev); pctrl->chip.parent = pctrl->dev; pctrl->chip.base = -1; @@ -1062,11 +1134,14 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) return ret; } - ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), - 0, 0, pctrl->soc->npins); - if (ret) { - dev_err(pctrl->dev, "failed to add GPIO pin range\n"); - return ret; + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + + ret = intel_gpio_add_pin_ranges(pctrl, community); + if (ret) { + dev_err(pctrl->dev, "failed to add GPIO pin range\n"); + return ret; + } } /* @@ -1126,6 +1201,9 @@ static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, if (gpps[i].size > 32) return -EINVAL; + if (!gpps[i].gpio_base) + gpps[i].gpio_base = gpps[i].base; + gpps[i].padown_num = padown_num; /* diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h index 13b0bd6eb2a2..98fdf9adf623 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.h +++ b/drivers/pinctrl/intel/pinctrl-intel.h @@ -51,6 +51,8 @@ struct intel_function { * @reg_num: GPI_IS register number * @base: Starting pin of this group * @size: Size of this group (maximum is 32). + * @gpio_base: Starting GPIO base of this group (%0 if matches with @base, + * and %-1 if no GPIO mapping should be created) * @padown_num: PAD_OWN register number (assigned by the core driver) * * If pad groups of a community are not the same size, use this structure @@ -60,6 +62,7 @@ struct intel_padgroup { unsigned reg_num; unsigned base; unsigned size; + int gpio_base; unsigned padown_num; }; -- cgit From cb5fda413e1d4a857bf4fd0bc92e9de0f1ff9e9d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 27 Nov 2017 16:54:44 +0300 Subject: pinctrl: cannonlake: Align GPIO number space with Windows The Cannon Lake Windows GPIO driver always exposes 32 pins per "bank" regardless of whether the hardware actually has that many pins in a pad group. This means that there are gaps in the GPIO number space even if such gaps do not exist in the real hardware. To make things worse the BIOS is also using the same scheme, so for example on Cannon Lake-LP vGPIO 39 (vSD3_CD_B) the ACPI GpioInt resource has number 231 instead of the expected 180 (which would be the hardware number). To make SD card detection and other GPIOs working properly in Linux we align the pinctrl-cannonlake GPIO numbering to follow the Windows GPIO driver numbering taking advantage of the gpio_base field introduced in the previous patch. Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-cannonlake.c | 65 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c index e130599be571..6243e7d95e7e 100644 --- a/drivers/pinctrl/intel/pinctrl-cannonlake.c +++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c @@ -23,13 +23,16 @@ #define CNL_HOSTSW_OWN 0x0b0 #define CNL_GPI_IE 0x120 -#define CNL_GPP(r, s, e) \ +#define CNL_GPP(r, s, e, g) \ { \ .reg_num = (r), \ .base = (s), \ .size = ((e) - (s) + 1), \ + .gpio_base = (g), \ } +#define CNL_NO_GPIO -1 + #define CNL_COMMUNITY(b, s, e, g) \ { \ .barno = (b), \ @@ -363,32 +366,32 @@ static const struct pinctrl_pin_desc cnlh_pins[] = { }; static const struct intel_padgroup cnlh_community0_gpps[] = { - CNL_GPP(0, 0, 24), /* GPP_A */ - CNL_GPP(1, 25, 50), /* GPP_B */ + CNL_GPP(0, 0, 24, 0), /* GPP_A */ + CNL_GPP(1, 25, 50, 32), /* GPP_B */ }; static const struct intel_padgroup cnlh_community1_gpps[] = { - CNL_GPP(0, 51, 74), /* GPP_C */ - CNL_GPP(1, 75, 98), /* GPP_D */ - CNL_GPP(2, 99, 106), /* GPP_G */ - CNL_GPP(3, 107, 114), /* AZA */ - CNL_GPP(4, 115, 146), /* vGPIO_0 */ - CNL_GPP(5, 147, 154), /* vGPIO_1 */ + 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, CNL_NO_GPIO), /* AZA */ + CNL_GPP(4, 115, 146, 160), /* vGPIO_0 */ + CNL_GPP(5, 147, 154, CNL_NO_GPIO), /* vGPIO_1 */ }; static const struct intel_padgroup cnlh_community3_gpps[] = { - CNL_GPP(0, 155, 178), /* GPP_K */ - CNL_GPP(1, 179, 202), /* GPP_H */ - CNL_GPP(2, 203, 215), /* GPP_E */ - CNL_GPP(3, 216, 239), /* GPP_F */ - CNL_GPP(4, 240, 248), /* SPI */ + CNL_GPP(0, 155, 178, 192), /* GPP_K */ + CNL_GPP(1, 179, 202, 224), /* GPP_H */ + CNL_GPP(2, 203, 215, 258), /* GPP_E */ + CNL_GPP(3, 216, 239, 288), /* GPP_F */ + CNL_GPP(4, 240, 248, CNL_NO_GPIO), /* SPI */ }; static const struct intel_padgroup cnlh_community4_gpps[] = { - CNL_GPP(0, 249, 259), /* CPU */ - CNL_GPP(1, 260, 268), /* JTAG */ - CNL_GPP(2, 269, 286), /* GPP_I */ - CNL_GPP(3, 287, 298), /* GPP_J */ + CNL_GPP(0, 249, 259, CNL_NO_GPIO), /* CPU */ + CNL_GPP(1, 260, 268, CNL_NO_GPIO), /* JTAG */ + CNL_GPP(2, 269, 286, 320), /* GPP_I */ + CNL_GPP(3, 287, 298, 352), /* GPP_J */ }; static const unsigned int cnlh_spi0_pins[] = { 40, 41, 42, 43 }; @@ -785,25 +788,25 @@ static const struct intel_function cnllp_functions[] = { }; static const struct intel_padgroup cnllp_community0_gpps[] = { - CNL_GPP(0, 0, 24), /* GPP_A */ - CNL_GPP(1, 25, 50), /* GPP_B */ - CNL_GPP(2, 51, 58), /* GPP_G */ - CNL_GPP(3, 59, 67), /* SPI */ + 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, CNL_NO_GPIO), /* SPI */ }; static const struct intel_padgroup cnllp_community1_gpps[] = { - CNL_GPP(0, 68, 92), /* GPP_D */ - CNL_GPP(1, 93, 116), /* GPP_F */ - CNL_GPP(2, 117, 140), /* GPP_H */ - CNL_GPP(3, 141, 172), /* vGPIO */ - CNL_GPP(4, 173, 180), /* vGPIO */ + 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 */ }; static const struct intel_padgroup cnllp_community4_gpps[] = { - CNL_GPP(0, 181, 204), /* GPP_C */ - CNL_GPP(1, 205, 228), /* GPP_E */ - CNL_GPP(2, 229, 237), /* JTAG */ - CNL_GPP(3, 238, 243), /* HVCMOS */ + CNL_GPP(0, 181, 204, 256), /* GPP_C */ + CNL_GPP(1, 205, 228, 288), /* GPP_E */ + CNL_GPP(2, 229, 237, CNL_NO_GPIO), /* JTAG */ + CNL_GPP(3, 238, 243, CNL_NO_GPIO), /* HVCMOS */ }; static const struct intel_community cnllp_communities[] = { -- cgit From 7f6f50dfb51b141ed2de277d8239c52f15d9742b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 30 Oct 2017 16:03:12 +0100 Subject: pinctrl: mcp23s08: Improve unlocking of a mutex in mcp23s08_irq() * Add a jump target so that a call of the function "mutex_unlock" is stored only twice in this function implementation. * Replace five calls by goto statements. * Adjust five condition checks. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-mcp23s08.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 4a6ea159c65d..e6ad36dea3e5 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -455,31 +455,22 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) defval_changed, gpio_set; mutex_lock(&mcp->lock); - if (mcp_read(mcp, MCP_INTF, &intf) < 0) { - mutex_unlock(&mcp->lock); - return IRQ_HANDLED; - } + if (mcp_read(mcp, MCP_INTF, &intf)) + goto unlock; - if (mcp_read(mcp, MCP_INTCAP, &intcap) < 0) { - mutex_unlock(&mcp->lock); - return IRQ_HANDLED; - } + if (mcp_read(mcp, MCP_INTCAP, &intcap)) + goto unlock; - if (mcp_read(mcp, MCP_INTCON, &intcon) < 0) { - mutex_unlock(&mcp->lock); - return IRQ_HANDLED; - } + if (mcp_read(mcp, MCP_INTCON, &intcon)) + goto unlock; - if (mcp_read(mcp, MCP_DEFVAL, &defval) < 0) { - mutex_unlock(&mcp->lock); - return IRQ_HANDLED; - } + if (mcp_read(mcp, MCP_DEFVAL, &defval)) + goto unlock; /* This clears the interrupt(configurable on S18) */ - if (mcp_read(mcp, MCP_GPIO, &gpio) < 0) { - mutex_unlock(&mcp->lock); - return IRQ_HANDLED; - } + if (mcp_read(mcp, MCP_GPIO, &gpio)) + goto unlock; + gpio_orig = mcp->cached_gpio; mcp->cached_gpio = gpio; mutex_unlock(&mcp->lock); @@ -541,6 +532,10 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) } return IRQ_HANDLED; + +unlock: + mutex_unlock(&mcp->lock); + return IRQ_HANDLED; } static void mcp23s08_irq_mask(struct irq_data *data) -- cgit From f2eef045de9defbc6fc6b72b17f0941cbe26c81d Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 18 Nov 2017 00:15:58 +0300 Subject: rtc: brcmstb-waketimer: fix error handling in brcmstb_waketmr_probe() brcmstb_waketmr_probe() does not disable timer->clk on error paths. Found by Linux Driver Verification project (linuxtesting.org). Fixes: c4f07ecee22e ("rtc: brcmstb-waketimer: Add Broadcom STB wake-timer") Signed-off-by: Alexey Khoroshilov Reviewed-by: Florian Fainelli Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-brcmstb-waketimer.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index 796ac792a381..6cee61201c30 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -253,7 +253,7 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0, "brcmstb-waketimer", timer); if (ret < 0) - return ret; + goto err_clk; timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot; register_reboot_notifier(&timer->reboot_notifier); @@ -262,12 +262,21 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) &brcmstb_waketmr_ops, THIS_MODULE); if (IS_ERR(timer->rtc)) { dev_err(dev, "unable to register device\n"); - unregister_reboot_notifier(&timer->reboot_notifier); - return PTR_ERR(timer->rtc); + ret = PTR_ERR(timer->rtc); + goto err_notifier; } dev_info(dev, "registered, with irq %d\n", timer->irq); + return 0; + +err_notifier: + unregister_reboot_notifier(&timer->reboot_notifier); + +err_clk: + if (timer->clk) + clk_disable_unprepare(timer->clk); + return ret; } -- cgit From 5c6e5eca79e8a5a89a7ae98b30ba6d71e367d899 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 18 Nov 2017 11:03:10 +0900 Subject: rtc: r9701: Remove r9701_remove function r9701_remove function is now empty, remove it. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-r9701.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 83d2bcca6a8f..b6c5eb97051c 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -164,17 +164,11 @@ static int r9701_probe(struct spi_device *spi) return 0; } -static int r9701_remove(struct spi_device *spi) -{ - return 0; -} - static struct spi_driver r9701_driver = { .driver = { .name = "rtc-r9701", }, .probe = r9701_probe, - .remove = r9701_remove, }; module_spi_driver(r9701_driver); -- cgit From 9f33399c90741196be71cc4637e623a7d33f8c7f Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Wed, 29 Nov 2017 15:26:44 +0100 Subject: rtc: stm32: Fix copyright Uniformize STMicroelectronics copyrights header Signed-off-by: Benjamin Gaignard CC: Amelie Delaunay Acked-by: Alexandre TORGUE Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3a5c3d7d0c77..f25dabe8fd02 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -1,6 +1,6 @@ /* - * Copyright (C) Amelie Delaunay 2016 - * Author: Amelie Delaunay + * Copyright (C) STMicroelectronics SA 2017 + * Author: Amelie Delaunay for STMicroelectronics. * License terms: GNU General Public License (GPL), version 2 */ -- cgit From 0fabe43f3f60e151e4a266049de66aa1fb4e2146 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Mon, 20 Nov 2017 18:08:24 +0800 Subject: pinctrl: meson-axg: Introduce a pinctrl pinmux ops for Meson-AXG SoC The pin controller has been updated in the Amlogic Meson AXG series, which use continuous 4-bit register to select function for each pin. In order to support this, a new pinmux operations "meson_axg_pmx_ops" has been added. Reviewed-by: Neil Armstrong Signed-off-by: Xingyu Chen Signed-off-by: Yixun Lan Reviewed-by: Jerome Brunet Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/Kconfig | 3 + drivers/pinctrl/meson/Makefile | 1 + drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c | 118 ++++++++++++++++++++++++++ drivers/pinctrl/meson/pinctrl-meson-axg-pmx.h | 62 ++++++++++++++ drivers/pinctrl/meson/pinctrl-meson.h | 1 + 5 files changed, 185 insertions(+) create mode 100644 drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c create mode 100644 drivers/pinctrl/meson/pinctrl-meson-axg-pmx.h (limited to 'drivers') diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index 1a51778759ea..fe5e6ca88412 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -38,4 +38,7 @@ config PINCTRL_MESON_GXL config PINCTRL_MESON8_PMX bool +config PINCTRL_MESON_AXG_PMX + bool + endif diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile index cbd47bb74549..8de839512677 100644 --- a/drivers/pinctrl/meson/Makefile +++ b/drivers/pinctrl/meson/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PINCTRL_MESON8) += pinctrl-meson8.o obj-$(CONFIG_PINCTRL_MESON8B) += pinctrl-meson8b.o obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o +obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c new file mode 100644 index 000000000000..e8931d9cf863 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c @@ -0,0 +1,118 @@ +/* + * Second generation of pinmux driver for Amlogic Meson-AXG SoC. + * + * Copyright (c) 2017 Baylibre SAS. + * Author: Jerome Brunet + * + * Copyright (c) 2017 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen + * + * SPDX-License-Identifier: (GPL-2.0+ or MIT) + */ + +/* + * This new generation of pinctrl IP is mainly adopted by the + * Meson-AXG SoC and later series, which use 4-width continuous + * register bit to select the function for each pin. + * + * The value 0 is always selecting the GPIO mode, while other + * values (start from 1) for selecting the function mode. + */ +#include +#include +#include +#include + +#include "pinctrl-meson.h" +#include "pinctrl-meson-axg-pmx.h" + +static int meson_axg_pmx_get_bank(struct meson_pinctrl *pc, + unsigned int pin, + struct meson_pmx_bank **bank) +{ + int i; + struct meson_axg_pmx_data *pmx = pc->data->pmx_data; + + for (i = 0; i < pmx->num_pmx_banks; i++) + if (pin >= pmx->pmx_banks[i].first && + pin <= pmx->pmx_banks[i].last) { + *bank = &pmx->pmx_banks[i]; + return 0; + } + + return -EINVAL; +} + +static int meson_pmx_calc_reg_and_offset(struct meson_pmx_bank *bank, + unsigned int pin, unsigned int *reg, + unsigned int *offset) +{ + int shift; + + shift = pin - bank->first; + + *reg = bank->reg + (bank->offset + (shift << 2)) / 32; + *offset = (bank->offset + (shift << 2)) % 32; + + return 0; +} + +static int meson_axg_pmx_update_function(struct meson_pinctrl *pc, + unsigned int pin, unsigned int func) +{ + int ret; + int reg; + int offset; + struct meson_pmx_bank *bank; + + ret = meson_axg_pmx_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_pmx_calc_reg_and_offset(bank, pin, ®, &offset); + + ret = regmap_update_bits(pc->reg_mux, reg << 2, + 0xf << offset, (func & 0xf) << offset); + + return ret; +} + +static int meson_axg_pmx_set_mux(struct pinctrl_dev *pcdev, + unsigned int func_num, unsigned int group_num) +{ + int i; + int ret; + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + struct meson_pmx_func *func = &pc->data->funcs[func_num]; + struct meson_pmx_group *group = &pc->data->groups[group_num]; + struct meson_pmx_axg_data *pmx_data = + (struct meson_pmx_axg_data *)group->data; + + dev_dbg(pc->dev, "enable function %s, group %s\n", func->name, + group->name); + + for (i = 0; i < group->num_pins; i++) { + ret = meson_axg_pmx_update_function(pc, group->pins[i], + pmx_data->func); + if (ret) + return ret; + } + + return 0; +} + +static int meson_axg_pmx_request_gpio(struct pinctrl_dev *pcdev, + struct pinctrl_gpio_range *range, unsigned int offset) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + return meson_axg_pmx_update_function(pc, offset, 0); +} + +const struct pinmux_ops meson_axg_pmx_ops = { + .set_mux = meson_axg_pmx_set_mux, + .get_functions_count = meson_pmx_get_funcs_count, + .get_function_name = meson_pmx_get_func_name, + .get_function_groups = meson_pmx_get_groups, + .gpio_request_enable = meson_axg_pmx_request_gpio, +}; diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.h b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.h new file mode 100644 index 000000000000..8ff88bf2e849 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017 Baylibre SAS. + * Author: Jerome Brunet + * + * Copyright (c) 2017 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen + * + * SPDX-License-Identifier: (GPL-2.0+ or MIT) + */ + +struct meson_pmx_bank { + const char *name; + unsigned int first; + unsigned int last; + unsigned int reg; + unsigned int offset; +}; + +struct meson_axg_pmx_data { + struct meson_pmx_bank *pmx_banks; + unsigned int num_pmx_banks; +}; + +#define BANK_PMX(n, f, l, r, o) \ + { \ + .name = n, \ + .first = f, \ + .last = l, \ + .reg = r, \ + .offset = o, \ + } + +struct meson_pmx_axg_data { + unsigned int func; +}; + +#define PMX_DATA(f) \ + { \ + .func = f, \ + } + +#define GROUP(grp, f) \ + { \ + .name = #grp, \ + .pins = grp ## _pins, \ + .num_pins = ARRAY_SIZE(grp ## _pins), \ + .data = (const struct meson_pmx_axg_data[]){ \ + PMX_DATA(f), \ + }, \ + } + +#define GPIO_GROUP(gpio) \ + { \ + .name = #gpio, \ + .pins = (const unsigned int[]){ gpio }, \ + .num_pins = 1, \ + .data = (const struct meson_pmx_axg_data[]){ \ + PMX_DATA(0), \ + }, \ + } + +extern const struct pinmux_ops meson_axg_pmx_ops; diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h index 183b6e471635..12a391109329 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.h +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -108,6 +108,7 @@ struct meson_pinctrl_data { struct meson_bank *banks; unsigned int num_banks; const struct pinmux_ops *pmx_ops; + void *pmx_data; }; struct meson_pinctrl { -- cgit From 83c566806a68a4b68cb87f5c605b8286d0b9f7a0 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Mon, 20 Nov 2017 18:08:25 +0800 Subject: pinctrl: meson-axg: Add new pinctrl driver for Meson AXG SoC Add new pinctrl driver for Amlogic's Meson-AXG SoC. Reviewed-by: Neil Armstrong Signed-off-by: Xingyu Chen Signed-off-by: Yixun Lan Reviewed-by: Jerome Brunet Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/Kconfig | 6 + drivers/pinctrl/meson/Makefile | 1 + drivers/pinctrl/meson/pinctrl-meson-axg.c | 975 ++++++++++++++++++++++++++++++ 3 files changed, 982 insertions(+) create mode 100644 drivers/pinctrl/meson/pinctrl-meson-axg.c (limited to 'drivers') diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index fe5e6ca88412..c80951d6caff 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -38,6 +38,12 @@ config PINCTRL_MESON_GXL config PINCTRL_MESON8_PMX bool +config PINCTRL_MESON_AXG + bool "Meson axg Soc pinctrl driver" + depends on ARM64 + select PINCTRL_MESON_AXG_PMX + default y + config PINCTRL_MESON_AXG_PMX bool diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile index 8de839512677..3c6580c2d9d7 100644 --- a/drivers/pinctrl/meson/Makefile +++ b/drivers/pinctrl/meson/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PINCTRL_MESON8B) += pinctrl-meson8b.o obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o +obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c new file mode 100644 index 000000000000..a1a7d42afd42 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c @@ -0,0 +1,975 @@ +/* + * Pin controller and GPIO driver for Amlogic Meson AXG SoC. + * + * Copyright (c) 2017 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen + * + * SPDX-License-Identifier: (GPL-2.0+ or MIT) + */ + +#include +#include "pinctrl-meson.h" +#include "pinctrl-meson-axg-pmx.h" + +static const struct pinctrl_pin_desc meson_axg_periphs_pins[] = { + MESON_PIN(GPIOZ_0), + MESON_PIN(GPIOZ_1), + MESON_PIN(GPIOZ_2), + MESON_PIN(GPIOZ_3), + MESON_PIN(GPIOZ_4), + MESON_PIN(GPIOZ_5), + MESON_PIN(GPIOZ_6), + MESON_PIN(GPIOZ_7), + MESON_PIN(GPIOZ_8), + MESON_PIN(GPIOZ_9), + MESON_PIN(GPIOZ_10), + MESON_PIN(BOOT_0), + MESON_PIN(BOOT_1), + MESON_PIN(BOOT_2), + MESON_PIN(BOOT_3), + MESON_PIN(BOOT_4), + MESON_PIN(BOOT_5), + MESON_PIN(BOOT_6), + MESON_PIN(BOOT_7), + MESON_PIN(BOOT_8), + MESON_PIN(BOOT_9), + MESON_PIN(BOOT_10), + MESON_PIN(BOOT_11), + MESON_PIN(BOOT_12), + MESON_PIN(BOOT_13), + MESON_PIN(BOOT_14), + MESON_PIN(GPIOA_0), + MESON_PIN(GPIOA_1), + MESON_PIN(GPIOA_2), + MESON_PIN(GPIOA_3), + MESON_PIN(GPIOA_4), + MESON_PIN(GPIOA_5), + MESON_PIN(GPIOA_6), + MESON_PIN(GPIOA_7), + MESON_PIN(GPIOA_8), + MESON_PIN(GPIOA_9), + MESON_PIN(GPIOA_10), + MESON_PIN(GPIOA_11), + MESON_PIN(GPIOA_12), + MESON_PIN(GPIOA_13), + MESON_PIN(GPIOA_14), + MESON_PIN(GPIOA_15), + MESON_PIN(GPIOA_16), + MESON_PIN(GPIOA_17), + MESON_PIN(GPIOA_18), + MESON_PIN(GPIOA_19), + MESON_PIN(GPIOA_20), + MESON_PIN(GPIOX_0), + MESON_PIN(GPIOX_1), + MESON_PIN(GPIOX_2), + MESON_PIN(GPIOX_3), + MESON_PIN(GPIOX_4), + MESON_PIN(GPIOX_5), + MESON_PIN(GPIOX_6), + MESON_PIN(GPIOX_7), + MESON_PIN(GPIOX_8), + MESON_PIN(GPIOX_9), + MESON_PIN(GPIOX_10), + MESON_PIN(GPIOX_11), + MESON_PIN(GPIOX_12), + MESON_PIN(GPIOX_13), + MESON_PIN(GPIOX_14), + MESON_PIN(GPIOX_15), + MESON_PIN(GPIOX_16), + MESON_PIN(GPIOX_17), + MESON_PIN(GPIOX_18), + MESON_PIN(GPIOX_19), + MESON_PIN(GPIOX_20), + MESON_PIN(GPIOX_21), + MESON_PIN(GPIOX_22), + MESON_PIN(GPIOY_0), + MESON_PIN(GPIOY_1), + MESON_PIN(GPIOY_2), + MESON_PIN(GPIOY_3), + MESON_PIN(GPIOY_4), + MESON_PIN(GPIOY_5), + MESON_PIN(GPIOY_6), + MESON_PIN(GPIOY_7), + MESON_PIN(GPIOY_8), + MESON_PIN(GPIOY_9), + MESON_PIN(GPIOY_10), + MESON_PIN(GPIOY_11), + MESON_PIN(GPIOY_12), + MESON_PIN(GPIOY_13), + MESON_PIN(GPIOY_14), + MESON_PIN(GPIOY_15), +}; + +static const struct pinctrl_pin_desc meson_axg_aobus_pins[] = { + MESON_PIN(GPIOAO_0), + MESON_PIN(GPIOAO_1), + MESON_PIN(GPIOAO_2), + MESON_PIN(GPIOAO_3), + MESON_PIN(GPIOAO_4), + MESON_PIN(GPIOAO_5), + MESON_PIN(GPIOAO_6), + MESON_PIN(GPIOAO_7), + MESON_PIN(GPIOAO_8), + MESON_PIN(GPIOAO_9), + MESON_PIN(GPIOAO_10), + MESON_PIN(GPIOAO_11), + MESON_PIN(GPIOAO_12), + MESON_PIN(GPIOAO_13), + MESON_PIN(GPIO_TEST_N), +}; + +/* emmc */ +static const unsigned int emmc_nand_d0_pins[] = {BOOT_0}; +static const unsigned int emmc_nand_d1_pins[] = {BOOT_1}; +static const unsigned int emmc_nand_d2_pins[] = {BOOT_2}; +static const unsigned int emmc_nand_d3_pins[] = {BOOT_3}; +static const unsigned int emmc_nand_d4_pins[] = {BOOT_4}; +static const unsigned int emmc_nand_d5_pins[] = {BOOT_5}; +static const unsigned int emmc_nand_d6_pins[] = {BOOT_6}; +static const unsigned int emmc_nand_d7_pins[] = {BOOT_7}; + +static const unsigned int emmc_clk_pins[] = {BOOT_8}; +static const unsigned int emmc_cmd_pins[] = {BOOT_10}; +static const unsigned int emmc_ds_pins[] = {BOOT_13}; + +/* nand */ +static const unsigned int nand_ce0_pins[] = {BOOT_8}; +static const unsigned int nand_ale_pins[] = {BOOT_9}; +static const unsigned int nand_cle_pins[] = {BOOT_10}; +static const unsigned int nand_wen_clk_pins[] = {BOOT_11}; +static const unsigned int nand_ren_wr_pins[] = {BOOT_12}; +static const unsigned int nand_rb0_pins[] = {BOOT_13}; + +/* nor */ +static const unsigned int nor_hold_pins[] = {BOOT_3}; +static const unsigned int nor_d_pins[] = {BOOT_4}; +static const unsigned int nor_q_pins[] = {BOOT_5}; +static const unsigned int nor_c_pins[] = {BOOT_6}; +static const unsigned int nor_wp_pins[] = {BOOT_9}; +static const unsigned int nor_cs_pins[] = {BOOT_14}; + +/* sdio */ +static const unsigned int sdio_d0_pins[] = {GPIOX_0}; +static const unsigned int sdio_d1_pins[] = {GPIOX_1}; +static const unsigned int sdio_d2_pins[] = {GPIOX_2}; +static const unsigned int sdio_d3_pins[] = {GPIOX_3}; +static const unsigned int sdio_clk_pins[] = {GPIOX_4}; +static const unsigned int sdio_cmd_pins[] = {GPIOX_5}; + +/* spi_a */ +static const unsigned int spi_clk_a_pins[] = {GPIOZ_0}; +static const unsigned int spi_mosi_a_pins[] = {GPIOZ_1}; +static const unsigned int spi_miso_a_pins[] = {GPIOZ_2}; +static const unsigned int spi_ss0_a_pins[] = {GPIOZ_3}; +static const unsigned int spi_ss1_a_pins[] = {GPIOZ_4}; +static const unsigned int spi_ss2_a_pins[] = {GPIOZ_5}; + +/* spi_b */ +static const unsigned int spi_clk_b_x_pins[] = {GPIOX_19}; +static const unsigned int spi_mosi_b_x_pins[] = {GPIOX_17}; +static const unsigned int spi_miso_b_x_pins[] = {GPIOX_18}; +static const unsigned int spi_ss0_b_x_pins[] = {GPIOX_16}; + +static const unsigned int spi_clk_b_a_pins[] = {GPIOA_4}; +static const unsigned int spi_mosi_b_a_pins[] = {GPIOA_2}; +static const unsigned int spi_miso_b_a_pins[] = {GPIOA_3}; +static const unsigned int spi_ss0_b_a_pins[] = {GPIOA_5}; +static const unsigned int spi_ss1_b_pins[] = {GPIOA_6}; + +/* i2c0 */ +static const unsigned int i2c0_sck_pins[] = {GPIOZ_6}; +static const unsigned int i2c0_sda_pins[] = {GPIOZ_7}; + +/* i2c1 */ +static const unsigned int i2c1_sck_z_pins[] = {GPIOZ_8}; +static const unsigned int i2c1_sda_z_pins[] = {GPIOZ_9}; + +static const unsigned int i2c1_sck_x_pins[] = {GPIOX_16}; +static const unsigned int i2c1_sda_x_pins[] = {GPIOX_17}; + +/* i2c2 */ +static const unsigned int i2c2_sck_x_pins[] = {GPIOX_18}; +static const unsigned int i2c2_sda_x_pins[] = {GPIOX_19}; + +static const unsigned int i2c2_sda_a_pins[] = {GPIOA_17}; +static const unsigned int i2c2_sck_a_pins[] = {GPIOA_18}; + +/* i2c3 */ +static const unsigned int i2c3_sda_a6_pins[] = {GPIOA_6}; +static const unsigned int i2c3_sck_a7_pins[] = {GPIOA_7}; + +static const unsigned int i2c3_sda_a12_pins[] = {GPIOA_12}; +static const unsigned int i2c3_sck_a13_pins[] = {GPIOA_13}; + +static const unsigned int i2c3_sda_a19_pins[] = {GPIOA_19}; +static const unsigned int i2c3_sck_a20_pins[] = {GPIOA_20}; + +/* uart_a */ +static const unsigned int uart_rts_a_pins[] = {GPIOX_11}; +static const unsigned int uart_cts_a_pins[] = {GPIOX_10}; +static const unsigned int uart_tx_a_pins[] = {GPIOX_8}; +static const unsigned int uart_rx_a_pins[] = {GPIOX_9}; + +/* uart_b */ +static const unsigned int uart_rts_b_z_pins[] = {GPIOZ_0}; +static const unsigned int uart_cts_b_z_pins[] = {GPIOZ_1}; +static const unsigned int uart_tx_b_z_pins[] = {GPIOZ_2}; +static const unsigned int uart_rx_b_z_pins[] = {GPIOZ_3}; + +static const unsigned int uart_rts_b_x_pins[] = {GPIOX_18}; +static const unsigned int uart_cts_b_x_pins[] = {GPIOX_19}; +static const unsigned int uart_tx_b_x_pins[] = {GPIOX_16}; +static const unsigned int uart_rx_b_x_pins[] = {GPIOX_17}; + +/* uart_ao_b */ +static const unsigned int uart_ao_tx_b_z_pins[] = {GPIOZ_8}; +static const unsigned int uart_ao_rx_b_z_pins[] = {GPIOZ_9}; +static const unsigned int uart_ao_cts_b_z_pins[] = {GPIOZ_6}; +static const unsigned int uart_ao_rts_b_z_pins[] = {GPIOZ_7}; + +/* pwm_a */ +static const unsigned int pwm_a_z_pins[] = {GPIOZ_5}; + +static const unsigned int pwm_a_x18_pins[] = {GPIOX_18}; +static const unsigned int pwm_a_x20_pins[] = {GPIOX_20}; + +static const unsigned int pwm_a_a_pins[] = {GPIOA_14}; + +/* pwm_b */ +static const unsigned int pwm_b_z_pins[] = {GPIOZ_4}; + +static const unsigned int pwm_b_x_pins[] = {GPIOX_19}; + +static const unsigned int pwm_b_a_pins[] = {GPIOA_15}; + +/* pwm_c */ +static const unsigned int pwm_c_x10_pins[] = {GPIOX_10}; +static const unsigned int pwm_c_x17_pins[] = {GPIOX_17}; + +static const unsigned int pwm_c_a_pins[] = {GPIOA_16}; + +/* pwm_d */ +static const unsigned int pwm_d_x11_pins[] = {GPIOX_11}; +static const unsigned int pwm_d_x16_pins[] = {GPIOX_16}; + +/* pwm_vs */ +static const unsigned int pwm_vs_pins[] = {GPIOA_0}; + +/* spdif_in */ +static const unsigned int spdif_in_z_pins[] = {GPIOZ_4}; + +static const unsigned int spdif_in_a1_pins[] = {GPIOA_1}; +static const unsigned int spdif_in_a7_pins[] = {GPIOA_7}; +static const unsigned int spdif_in_a19_pins[] = {GPIOA_19}; +static const unsigned int spdif_in_a20_pins[] = {GPIOA_20}; + +/* spdif_out */ +static const unsigned int spdif_out_z_pins[] = {GPIOZ_5}; + +static const unsigned int spdif_out_a1_pins[] = {GPIOA_1}; +static const unsigned int spdif_out_a11_pins[] = {GPIOA_11}; +static const unsigned int spdif_out_a19_pins[] = {GPIOA_19}; +static const unsigned int spdif_out_a20_pins[] = {GPIOA_20}; + +/* jtag_ee */ +static const unsigned int jtag_tdo_x_pins[] = {GPIOX_0}; +static const unsigned int jtag_tdi_x_pins[] = {GPIOX_1}; +static const unsigned int jtag_clk_x_pins[] = {GPIOX_4}; +static const unsigned int jtag_tms_x_pins[] = {GPIOX_5}; + +/* eth */ +static const unsigned int eth_txd0_x_pins[] = {GPIOX_8}; +static const unsigned int eth_txd1_x_pins[] = {GPIOX_9}; +static const unsigned int eth_txen_x_pins[] = {GPIOX_10}; +static const unsigned int eth_rgmii_rx_clk_x_pins[] = {GPIOX_12}; +static const unsigned int eth_rxd0_x_pins[] = {GPIOX_13}; +static const unsigned int eth_rxd1_x_pins[] = {GPIOX_14}; +static const unsigned int eth_rx_dv_x_pins[] = {GPIOX_15}; +static const unsigned int eth_mdio_x_pins[] = {GPIOX_21}; +static const unsigned int eth_mdc_x_pins[] = {GPIOX_22}; + +static const unsigned int eth_txd0_y_pins[] = {GPIOY_10}; +static const unsigned int eth_txd1_y_pins[] = {GPIOY_11}; +static const unsigned int eth_txen_y_pins[] = {GPIOY_9}; +static const unsigned int eth_rgmii_rx_clk_y_pins[] = {GPIOY_2}; +static const unsigned int eth_rxd0_y_pins[] = {GPIOY_4}; +static const unsigned int eth_rxd1_y_pins[] = {GPIOY_5}; +static const unsigned int eth_rx_dv_y_pins[] = {GPIOY_3}; +static const unsigned int eth_mdio_y_pins[] = {GPIOY_0}; +static const unsigned int eth_mdc_y_pins[] = {GPIOY_1}; + +static const unsigned int eth_rxd2_rgmii_pins[] = {GPIOY_6}; +static const unsigned int eth_rxd3_rgmii_pins[] = {GPIOY_7}; +static const unsigned int eth_rgmii_tx_clk_pins[] = {GPIOY_8}; +static const unsigned int eth_txd2_rgmii_pins[] = {GPIOY_12}; +static const unsigned int eth_txd3_rgmii_pins[] = {GPIOY_13}; + +/* pdm */ +static const unsigned int pdm_dclk_a14_pins[] = {GPIOA_14}; +static const unsigned int pdm_dclk_a19_pins[] = {GPIOA_19}; +static const unsigned int pdm_din0_pins[] = {GPIOA_15}; +static const unsigned int pdm_din1_pins[] = {GPIOA_16}; +static const unsigned int pdm_din2_pins[] = {GPIOA_17}; +static const unsigned int pdm_din3_pins[] = {GPIOA_18}; + +static struct meson_pmx_group meson_axg_periphs_groups[] = { + GPIO_GROUP(GPIOZ_0), + GPIO_GROUP(GPIOZ_1), + GPIO_GROUP(GPIOZ_2), + GPIO_GROUP(GPIOZ_3), + GPIO_GROUP(GPIOZ_4), + GPIO_GROUP(GPIOZ_5), + GPIO_GROUP(GPIOZ_6), + GPIO_GROUP(GPIOZ_7), + GPIO_GROUP(GPIOZ_8), + GPIO_GROUP(GPIOZ_9), + GPIO_GROUP(GPIOZ_10), + + GPIO_GROUP(BOOT_0), + GPIO_GROUP(BOOT_1), + GPIO_GROUP(BOOT_2), + GPIO_GROUP(BOOT_3), + GPIO_GROUP(BOOT_4), + GPIO_GROUP(BOOT_5), + GPIO_GROUP(BOOT_6), + GPIO_GROUP(BOOT_7), + GPIO_GROUP(BOOT_8), + GPIO_GROUP(BOOT_9), + GPIO_GROUP(BOOT_10), + GPIO_GROUP(BOOT_11), + GPIO_GROUP(BOOT_12), + GPIO_GROUP(BOOT_13), + GPIO_GROUP(BOOT_14), + + GPIO_GROUP(GPIOA_0), + GPIO_GROUP(GPIOA_1), + GPIO_GROUP(GPIOA_2), + GPIO_GROUP(GPIOA_3), + GPIO_GROUP(GPIOA_4), + GPIO_GROUP(GPIOA_5), + GPIO_GROUP(GPIOA_6), + GPIO_GROUP(GPIOA_7), + GPIO_GROUP(GPIOA_8), + GPIO_GROUP(GPIOA_9), + GPIO_GROUP(GPIOA_10), + GPIO_GROUP(GPIOA_11), + GPIO_GROUP(GPIOA_12), + GPIO_GROUP(GPIOA_13), + GPIO_GROUP(GPIOA_14), + GPIO_GROUP(GPIOA_15), + GPIO_GROUP(GPIOA_16), + GPIO_GROUP(GPIOA_17), + GPIO_GROUP(GPIOA_19), + GPIO_GROUP(GPIOA_20), + + GPIO_GROUP(GPIOX_0), + GPIO_GROUP(GPIOX_1), + GPIO_GROUP(GPIOX_2), + GPIO_GROUP(GPIOX_3), + GPIO_GROUP(GPIOX_4), + GPIO_GROUP(GPIOX_5), + GPIO_GROUP(GPIOX_6), + GPIO_GROUP(GPIOX_7), + GPIO_GROUP(GPIOX_8), + GPIO_GROUP(GPIOX_9), + GPIO_GROUP(GPIOX_10), + GPIO_GROUP(GPIOX_11), + GPIO_GROUP(GPIOX_12), + GPIO_GROUP(GPIOX_13), + GPIO_GROUP(GPIOX_14), + GPIO_GROUP(GPIOX_15), + GPIO_GROUP(GPIOX_16), + GPIO_GROUP(GPIOX_17), + GPIO_GROUP(GPIOX_18), + GPIO_GROUP(GPIOX_19), + GPIO_GROUP(GPIOX_20), + GPIO_GROUP(GPIOX_21), + GPIO_GROUP(GPIOX_22), + + GPIO_GROUP(GPIOY_0), + GPIO_GROUP(GPIOY_1), + GPIO_GROUP(GPIOY_2), + GPIO_GROUP(GPIOY_3), + GPIO_GROUP(GPIOY_4), + GPIO_GROUP(GPIOY_5), + GPIO_GROUP(GPIOY_6), + GPIO_GROUP(GPIOY_7), + GPIO_GROUP(GPIOY_8), + GPIO_GROUP(GPIOY_9), + GPIO_GROUP(GPIOY_10), + GPIO_GROUP(GPIOY_11), + GPIO_GROUP(GPIOY_12), + GPIO_GROUP(GPIOY_13), + GPIO_GROUP(GPIOY_14), + GPIO_GROUP(GPIOY_15), + + /* bank BOOT */ + GROUP(emmc_nand_d0, 1), + GROUP(emmc_nand_d1, 1), + GROUP(emmc_nand_d2, 1), + GROUP(emmc_nand_d3, 1), + GROUP(emmc_nand_d4, 1), + GROUP(emmc_nand_d5, 1), + GROUP(emmc_nand_d6, 1), + GROUP(emmc_nand_d7, 1), + GROUP(emmc_clk, 1), + GROUP(emmc_cmd, 1), + GROUP(emmc_ds, 1), + GROUP(nand_ce0, 2), + GROUP(nand_ale, 2), + GROUP(nand_cle, 2), + GROUP(nand_wen_clk, 2), + GROUP(nand_ren_wr, 2), + GROUP(nand_rb0, 2), + GROUP(nor_hold, 3), + GROUP(nor_d, 3), + GROUP(nor_q, 3), + GROUP(nor_c, 3), + GROUP(nor_wp, 3), + GROUP(nor_cs, 3), + + /* bank GPIOZ */ + GROUP(spi_clk_a, 1), + GROUP(spi_mosi_a, 1), + GROUP(spi_miso_a, 1), + GROUP(spi_ss0_a, 1), + GROUP(spi_ss1_a, 1), + GROUP(spi_ss2_a, 1), + GROUP(i2c0_sck, 1), + GROUP(i2c0_sda, 1), + GROUP(i2c1_sck_z, 1), + GROUP(i2c1_sda_z, 1), + GROUP(uart_rts_b_z, 2), + GROUP(uart_cts_b_z, 2), + GROUP(uart_tx_b_z, 2), + GROUP(uart_rx_b_z, 2), + GROUP(pwm_a_z, 2), + GROUP(pwm_b_z, 2), + GROUP(spdif_in_z, 3), + GROUP(spdif_out_z, 3), + GROUP(uart_ao_tx_b_z, 2), + GROUP(uart_ao_rx_b_z, 2), + GROUP(uart_ao_cts_b_z, 2), + GROUP(uart_ao_rts_b_z, 2), + + /* bank GPIOX */ + GROUP(sdio_d0, 1), + GROUP(sdio_d1, 1), + GROUP(sdio_d2, 1), + GROUP(sdio_d3, 1), + GROUP(sdio_clk, 1), + GROUP(sdio_cmd, 1), + GROUP(i2c1_sck_x, 1), + GROUP(i2c1_sda_x, 1), + GROUP(i2c2_sck_x, 1), + GROUP(i2c2_sda_x, 1), + GROUP(uart_rts_a, 1), + GROUP(uart_cts_a, 1), + GROUP(uart_tx_a, 1), + GROUP(uart_rx_a, 1), + GROUP(uart_rts_b_x, 2), + GROUP(uart_cts_b_x, 2), + GROUP(uart_tx_b_x, 2), + GROUP(uart_rx_b_x, 2), + GROUP(jtag_tdo_x, 2), + GROUP(jtag_tdi_x, 2), + GROUP(jtag_clk_x, 2), + GROUP(jtag_tms_x, 2), + GROUP(spi_clk_b_x, 4), + GROUP(spi_mosi_b_x, 4), + GROUP(spi_miso_b_x, 4), + GROUP(spi_ss0_b_x, 4), + GROUP(pwm_a_x18, 3), + GROUP(pwm_a_x20, 1), + GROUP(pwm_b_x, 3), + GROUP(pwm_c_x10, 3), + GROUP(pwm_c_x17, 3), + GROUP(pwm_d_x11, 3), + GROUP(pwm_d_x16, 3), + GROUP(eth_txd0_x, 4), + GROUP(eth_txd1_x, 4), + GROUP(eth_txen_x, 4), + GROUP(eth_rgmii_rx_clk_x, 4), + GROUP(eth_rxd0_x, 4), + GROUP(eth_rxd1_x, 4), + GROUP(eth_rx_dv_x, 4), + GROUP(eth_mdio_x, 4), + GROUP(eth_mdc_x, 4), + + /* bank GPIOY */ + GROUP(eth_txd0_y, 1), + GROUP(eth_txd1_y, 1), + GROUP(eth_txen_y, 1), + GROUP(eth_rgmii_rx_clk_y, 1), + GROUP(eth_rxd0_y, 1), + GROUP(eth_rxd1_y, 1), + GROUP(eth_rx_dv_y, 1), + GROUP(eth_mdio_y, 1), + GROUP(eth_mdc_y, 1), + GROUP(eth_rxd2_rgmii, 1), + GROUP(eth_rxd3_rgmii, 1), + GROUP(eth_rgmii_tx_clk, 1), + GROUP(eth_txd2_rgmii, 1), + GROUP(eth_txd3_rgmii, 1), + + /* bank GPIOA */ + GROUP(spdif_out_a1, 4), + GROUP(spdif_out_a11, 3), + GROUP(spdif_out_a19, 2), + GROUP(spdif_out_a20, 1), + GROUP(spdif_in_a1, 3), + GROUP(spdif_in_a7, 3), + GROUP(spdif_in_a19, 1), + GROUP(spdif_in_a20, 2), + GROUP(spi_clk_b_a, 3), + GROUP(spi_mosi_b_a, 3), + GROUP(spi_miso_b_a, 3), + GROUP(spi_ss0_b_a, 3), + GROUP(spi_ss1_b, 3), + GROUP(pwm_a_a, 3), + GROUP(pwm_b_a, 3), + GROUP(pwm_c_a, 3), + GROUP(pwm_vs, 2), + GROUP(i2c2_sda_a, 3), + GROUP(i2c2_sck_a, 3), + GROUP(i2c3_sda_a6, 4), + GROUP(i2c3_sck_a7, 4), + GROUP(i2c3_sda_a12, 4), + GROUP(i2c3_sck_a13, 4), + GROUP(i2c3_sda_a19, 4), + GROUP(i2c3_sck_a20, 4), + GROUP(pdm_dclk_a14, 1), + GROUP(pdm_dclk_a19, 3), + GROUP(pdm_din0, 1), + GROUP(pdm_din1, 1), + GROUP(pdm_din2, 1), + GROUP(pdm_din3, 1), +}; + +/* uart_ao_a */ +static const unsigned int uart_ao_tx_a_pins[] = {GPIOAO_0}; +static const unsigned int uart_ao_rx_a_pins[] = {GPIOAO_1}; +static const unsigned int uart_ao_cts_a_pins[] = {GPIOAO_2}; +static const unsigned int uart_ao_rts_a_pins[] = {GPIOAO_3}; + +/* uart_ao_b */ +static const unsigned int uart_ao_tx_b_pins[] = {GPIOAO_4}; +static const unsigned int uart_ao_rx_b_pins[] = {GPIOAO_5}; +static const unsigned int uart_ao_cts_b_pins[] = {GPIOAO_2}; +static const unsigned int uart_ao_rts_b_pins[] = {GPIOAO_3}; + +/* i2c_ao */ +static const unsigned int i2c_ao_sck_4_pins[] = {GPIOAO_4}; +static const unsigned int i2c_ao_sda_5_pins[] = {GPIOAO_5}; +static const unsigned int i2c_ao_sck_8_pins[] = {GPIOAO_8}; +static const unsigned int i2c_ao_sda_9_pins[] = {GPIOAO_9}; +static const unsigned int i2c_ao_sck_10_pins[] = {GPIOAO_10}; +static const unsigned int i2c_ao_sda_11_pins[] = {GPIOAO_11}; + +/* i2c_ao_slave */ +static const unsigned int i2c_ao_slave_sck_pins[] = {GPIOAO_10}; +static const unsigned int i2c_ao_slave_sda_pins[] = {GPIOAO_11}; + +/* ir_in */ +static const unsigned int remote_input_ao_pins[] = {GPIOAO_6}; + +/* ir_out */ +static const unsigned int remote_out_ao_pins[] = {GPIOAO_7}; + +/* pwm_ao_a */ +static const unsigned int pwm_ao_a_pins[] = {GPIOAO_3}; + +/* pwm_ao_b */ +static const unsigned int pwm_ao_b_ao2_pins[] = {GPIOAO_2}; +static const unsigned int pwm_ao_b_ao12_pins[] = {GPIOAO_12}; + +/* pwm_ao_c */ +static const unsigned int pwm_ao_c_ao8_pins[] = {GPIOAO_8}; +static const unsigned int pwm_ao_c_ao13_pins[] = {GPIOAO_13}; + +/* pwm_ao_d */ +static const unsigned int pwm_ao_d_pins[] = {GPIOAO_9}; + +/* jtag_ao */ +static const unsigned int jtag_ao_tdi_pins[] = {GPIOAO_3}; +static const unsigned int jtag_ao_tdo_pins[] = {GPIOAO_4}; +static const unsigned int jtag_ao_clk_pins[] = {GPIOAO_5}; +static const unsigned int jtag_ao_tms_pins[] = {GPIOAO_7}; + +static struct meson_pmx_group meson_axg_aobus_groups[] = { + GPIO_GROUP(GPIOAO_0), + GPIO_GROUP(GPIOAO_1), + GPIO_GROUP(GPIOAO_2), + GPIO_GROUP(GPIOAO_3), + GPIO_GROUP(GPIOAO_4), + GPIO_GROUP(GPIOAO_5), + GPIO_GROUP(GPIOAO_6), + GPIO_GROUP(GPIOAO_7), + GPIO_GROUP(GPIOAO_8), + GPIO_GROUP(GPIOAO_9), + GPIO_GROUP(GPIOAO_10), + GPIO_GROUP(GPIOAO_11), + GPIO_GROUP(GPIOAO_12), + GPIO_GROUP(GPIOAO_13), + GPIO_GROUP(GPIO_TEST_N), + + /* bank AO */ + GROUP(uart_ao_tx_a, 1), + GROUP(uart_ao_rx_a, 1), + GROUP(uart_ao_cts_a, 2), + GROUP(uart_ao_rts_a, 2), + GROUP(uart_ao_tx_b, 1), + GROUP(uart_ao_rx_b, 1), + GROUP(uart_ao_cts_b, 1), + GROUP(uart_ao_rts_b, 1), + GROUP(i2c_ao_sck_4, 2), + GROUP(i2c_ao_sda_5, 2), + GROUP(i2c_ao_sck_8, 2), + GROUP(i2c_ao_sda_9, 2), + GROUP(i2c_ao_sck_10, 2), + GROUP(i2c_ao_sda_11, 2), + GROUP(i2c_ao_slave_sck, 1), + GROUP(i2c_ao_slave_sda, 1), + GROUP(remote_input_ao, 1), + GROUP(remote_out_ao, 1), + GROUP(pwm_ao_a, 3), + GROUP(pwm_ao_b_ao2, 3), + GROUP(pwm_ao_b_ao12, 3), + GROUP(pwm_ao_c_ao8, 3), + GROUP(pwm_ao_c_ao13, 3), + GROUP(pwm_ao_d, 3), + GROUP(jtag_ao_tdi, 4), + GROUP(jtag_ao_tdo, 4), + GROUP(jtag_ao_clk, 4), + GROUP(jtag_ao_tms, 4), +}; + +static const char * const gpio_periphs_groups[] = { + "GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4", + "GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9", + "GPIOZ_10", + + "BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4", + "BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9", + "BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14", + + "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", + "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", + "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", + "GPIOA_15", "GPIOA_16", "GPIOA_17", "GPIOA_18", "GPIOA_19", + "GPIOA_20", + + "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4", + "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9", + "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14", + "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19", + "GPIOX_20", "GPIOX_21", "GPIOX_22", + + "GPIOY_0", "GPIOY_1", "GPIOY_2", "GPIOY_3", "GPIOY_4", + "GPIOY_5", "GPIOY_6", "GPIOY_7", "GPIOY_8", "GPIOY_9", + "GPIOY_10", "GPIOY_11", "GPIOY_12", "GPIOY_13", "GPIOY_14", + "GPIOY_15", +}; + +static const char * const emmc_groups[] = { + "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2", + "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5", + "emmc_nand_d6", "emmc_nand_d7", + "emmc_clk", "emmc_cmd", "emmc_ds", +}; + +static const char * const nand_groups[] = { + "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2", + "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5", + "emmc_nand_d6", "emmc_nand_d7", + "nand_ce0", "nand_ale", "nand_cle", + "nand_wen_clk", "nand_ren_wr", "nand_rb0", +}; + +static const char * const nor_groups[] = { + "nor_d", "nor_q", "nor_c", "nor_cs", + "nor_hold", "nor_wp", +}; + +static const char * const sdio_groups[] = { + "sdio_d0", "sdio_d1", "sdio_d2", "sdio_d3", + "sdio_cmd", "sdio_clk", +}; + +static const char * const spi_a_groups[] = { + "spi_clk_a", "spi_mosi_a", "spi_miso_a", "spi_ss0_a", + "spi_ss1_a", "spi_ss2_a" +}; + +static const char * const spi_b_groups[] = { + "spi_clk_b_x", "spi_mosi_b_x", "spi_miso_b_x", "spi_ss0_b_x", + "spi_clk_b_a", "spi_mosi_b_a", "spi_miso_b_a", "spi_ss0_b_a", + "spi_ss1_b" +}; + +static const char * const uart_a_groups[] = { + "uart_tx_a", "uart_rx_a", "uart_cts_a", "uart_rts_a", +}; + +static const char * const uart_b_groups[] = { + "uart_tx_b_z", "uart_rx_b_z", "uart_cts_b_z", "uart_rts_b_z", + "uart_tx_b_x", "uart_rx_b_x", "uart_cts_b_x", "uart_rts_b_x", +}; + +static const char * const uart_ao_b_gpioz_groups[] = { + "uart_ao_tx_b_z", "uart_ao_rx_b_z", + "uart_ao_cts_b_z", "uart_ao_rts_b_z", +}; + +static const char * const i2c0_groups[] = { + "i2c0_sck", "i2c0_sda", +}; + +static const char * const i2c1_groups[] = { + "i2c1_sck_z", "i2c1_sda_z", + "i2c1_sck_x", "i2c1_sda_x", +}; + +static const char * const i2c2_groups[] = { + "i2c2_sck_x", "i2c2_sda_x", + "i2c2_sda_a", "i2c2_sck_a", +}; + +static const char * const i2c3_groups[] = { + "i2c3_sda_a6", "i2c3_sck_a7", + "i2c3_sda_a12", "i2c3_sck_a13", + "i2c3_sda_a19", "i2c3_sck_a20", +}; + +static const char * const eth_groups[] = { + "eth_rxd2_rgmii", "eth_rxd3_rgmii", "eth_rgmii_tx_clk", + "eth_txd2_rgmii", "eth_txd3_rgmii", + "eth_txd0_x", "eth_txd1_x", "eth_txen_x", "eth_rgmii_rx_clk_x", + "eth_rxd0_x", "eth_rxd1_x", "eth_rx_dv_x", "eth_mdio_x", + "eth_mdc_x", + "eth_txd0_y", "eth_txd1_y", "eth_txen_y", "eth_rgmii_rx_clk_y", + "eth_rxd0_y", "eth_rxd1_y", "eth_rx_dv_y", "eth_mdio_y", + "eth_mdc_y", +}; + +static const char * const pwm_a_groups[] = { + "pwm_a_z", "pwm_a_x18", "pwm_a_x20", "pwm_a_a", +}; + +static const char * const pwm_b_groups[] = { + "pwm_b_z", "pwm_b_x", "pwm_b_a", +}; + +static const char * const pwm_c_groups[] = { + "pwm_c_x10", "pwm_c_x17", "pwm_c_a", +}; + +static const char * const pwm_d_groups[] = { + "pwm_d_x11", "pwm_d_x16", +}; + +static const char * const pwm_vs_groups[] = { + "pwm_vs", +}; + +static const char * const spdif_out_groups[] = { + "spdif_out_z", "spdif_out_a1", "spdif_out_a11", + "spdif_out_a19", "spdif_out_a20", +}; + +static const char * const spdif_in_groups[] = { + "spdif_in_z", "spdif_in_a1", "spdif_in_a7", + "spdif_in_a19", "spdif_in_a20", +}; + +static const char * const jtag_ee_groups[] = { + "jtag_tdo_x", "jtag_tdi_x", "jtag_clk_x", + "jtag_tms_x", +}; + +static const char * const pdm_groups[] = { + "pdm_din0", "pdm_din1", "pdm_din2", "pdm_din3", + "pdm_dclk_a14", "pdm_dclk_a19", +}; + +static const char * const gpio_aobus_groups[] = { + "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4", + "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9", + "GPIOAO_10", "GPIOAO_11", "GPIOAO_12", "GPIOAO_13", + "GPIO_TEST_N", +}; + +static const char * const uart_ao_a_groups[] = { + "uart_ao_tx_a", "uart_ao_rx_a", "uart_ao_cts_a", "uart_ao_rts_a", +}; + +static const char * const uart_ao_b_groups[] = { + "uart_ao_tx_b", "uart_ao_rx_b", "uart_ao_cts_b", "uart_ao_rts_b", +}; + +static const char * const i2c_ao_groups[] = { + "i2c_ao_sck_4", "i2c_ao_sda_5", + "i2c_ao_sck_8", "i2c_ao_sda_9", + "i2c_ao_sck_10", "i2c_ao_sda_11", +}; + +static const char * const i2c_ao_slave_groups[] = { + "i2c_ao_slave_sck", "i2c_ao_slave_sda", +}; + +static const char * const remote_input_ao_groups[] = { + "remote_input_ao", +}; + +static const char * const remote_out_ao_groups[] = { + "remote_out_ao", +}; + +static const char * const pwm_ao_a_groups[] = { + "pwm_ao_a", +}; + +static const char * const pwm_ao_b_groups[] = { + "pwm_ao_b_ao2", "pwm_ao_b_ao12", +}; + +static const char * const pwm_ao_c_groups[] = { + "pwm_ao_c_ao8", "pwm_ao_c_ao13", +}; + +static const char * const pwm_ao_d_groups[] = { + "pwm_ao_d", +}; + +static const char * const jtag_ao_groups[] = { + "jtag_ao_tdi", "jtag_ao_tdo", "jtag_ao_clk", "jtag_ao_tms", +}; + +static struct meson_pmx_func meson_axg_periphs_functions[] = { + FUNCTION(gpio_periphs), + FUNCTION(emmc), + FUNCTION(nor), + FUNCTION(spi_a), + FUNCTION(spi_b), + FUNCTION(sdio), + FUNCTION(nand), + FUNCTION(uart_a), + FUNCTION(uart_b), + FUNCTION(uart_ao_b_gpioz), + FUNCTION(i2c0), + FUNCTION(i2c1), + FUNCTION(i2c2), + FUNCTION(i2c3), + FUNCTION(eth), + FUNCTION(pwm_a), + FUNCTION(pwm_b), + FUNCTION(pwm_c), + FUNCTION(pwm_d), + FUNCTION(pwm_vs), + FUNCTION(spdif_out), + FUNCTION(spdif_in), + FUNCTION(jtag_ee), + FUNCTION(pdm), +}; + +static struct meson_pmx_func meson_axg_aobus_functions[] = { + FUNCTION(gpio_aobus), + FUNCTION(uart_ao_a), + FUNCTION(uart_ao_b), + FUNCTION(i2c_ao), + FUNCTION(i2c_ao_slave), + FUNCTION(remote_input_ao), + FUNCTION(remote_out_ao), + FUNCTION(pwm_ao_a), + FUNCTION(pwm_ao_b), + FUNCTION(pwm_ao_c), + FUNCTION(pwm_ao_d), + FUNCTION(jtag_ao), +}; + +static struct meson_bank meson_axg_periphs_banks[] = { + /* name first last irq pullen pull dir out in */ + BANK("Z", GPIOZ_0, GPIOZ_10, 14, 24, 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), + BANK("BOOT", BOOT_0, BOOT_14, 25, 39, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), + BANK("A", GPIOA_0, GPIOA_20, 40, 60, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), + BANK("X", GPIOX_0, GPIOX_22, 61, 83, 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), + BANK("Y", GPIOY_0, GPIOY_15, 84, 99, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), +}; + +static struct meson_bank meson_axg_aobus_banks[] = { + /* name first last irq pullen pull dir out in */ + BANK("AO", GPIOAO_0, GPIOAO_9, 0, 13, 0, 16, 0, 0, 0, 0, 0, 16, 1, 0), +}; + +static struct meson_pmx_bank meson_axg_periphs_pmx_banks[] = { + /* name first lask reg offset */ + BANK_PMX("Z", GPIOZ_0, GPIOZ_10, 0x2, 0), + BANK_PMX("BOOT", BOOT_0, BOOT_14, 0x0, 0), + BANK_PMX("A", GPIOA_0, GPIOA_20, 0xb, 0), + BANK_PMX("X", GPIOX_0, GPIOX_22, 0x4, 0), + BANK_PMX("Y", GPIOY_0, GPIOY_15, 0x8, 0), +}; + +static struct meson_axg_pmx_data meson_axg_periphs_pmx_banks_data = { + .pmx_banks = meson_axg_periphs_pmx_banks, + .num_pmx_banks = ARRAY_SIZE(meson_axg_periphs_pmx_banks), +}; + +static struct meson_pmx_bank meson_axg_aobus_pmx_banks[] = { + BANK_PMX("AO", GPIOAO_0, GPIOAO_13, 0x0, 0), +}; + +static struct meson_axg_pmx_data meson_axg_aobus_pmx_banks_data = { + .pmx_banks = meson_axg_aobus_pmx_banks, + .num_pmx_banks = ARRAY_SIZE(meson_axg_aobus_pmx_banks), +}; + +static struct meson_pinctrl_data meson_axg_periphs_pinctrl_data = { + .name = "periphs-banks", + .pins = meson_axg_periphs_pins, + .groups = meson_axg_periphs_groups, + .funcs = meson_axg_periphs_functions, + .banks = meson_axg_periphs_banks, + .num_pins = ARRAY_SIZE(meson_axg_periphs_pins), + .num_groups = ARRAY_SIZE(meson_axg_periphs_groups), + .num_funcs = ARRAY_SIZE(meson_axg_periphs_functions), + .num_banks = ARRAY_SIZE(meson_axg_periphs_banks), + .pmx_ops = &meson_axg_pmx_ops, + .pmx_data = &meson_axg_periphs_pmx_banks_data, +}; + +static struct meson_pinctrl_data meson_axg_aobus_pinctrl_data = { + .name = "aobus-banks", + .pins = meson_axg_aobus_pins, + .groups = meson_axg_aobus_groups, + .funcs = meson_axg_aobus_functions, + .banks = meson_axg_aobus_banks, + .num_pins = ARRAY_SIZE(meson_axg_aobus_pins), + .num_groups = ARRAY_SIZE(meson_axg_aobus_groups), + .num_funcs = ARRAY_SIZE(meson_axg_aobus_functions), + .num_banks = ARRAY_SIZE(meson_axg_aobus_banks), + .pmx_ops = &meson_axg_pmx_ops, + .pmx_data = &meson_axg_aobus_pmx_banks_data, +}; + +static const struct of_device_id meson_axg_pinctrl_dt_match[] = { + { + .compatible = "amlogic,meson-axg-periphs-pinctrl", + .data = &meson_axg_periphs_pinctrl_data, + }, + { + .compatible = "amlogic,meson-axg-aobus-pinctrl", + .data = &meson_axg_aobus_pinctrl_data, + }, + { }, +}; + +static struct platform_driver meson_axg_pinctrl_driver = { + .probe = meson_pinctrl_probe, + .driver = { + .name = "meson-axg-pinctrl", + .of_match_table = meson_axg_pinctrl_dt_match, + }, +}; + +builtin_platform_driver(meson_axg_pinctrl_driver); -- cgit From 9c957fcecb5dad684b156d170b50e48636f3ded1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 19 Nov 2017 10:57:27 +0100 Subject: pinctrl: gemini: Add two missing GPIO groups The 3512 has two more GPIO groups on GPIO area 0, so let's make it possible to combine these with the function. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-gemini.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-gemini.c b/drivers/pinctrl/pinctrl-gemini.c index e9b83e291edf..10f8f3a35fe1 100644 --- a/drivers/pinctrl/pinctrl-gemini.c +++ b/drivers/pinctrl/pinctrl-gemini.c @@ -2015,7 +2015,8 @@ static const char * const sflashgrps[] = { "sflashgrp" }; static const char * const gpio0grps[] = { "gpio0agrp", "gpio0bgrp", "gpio0cgrp", "gpio0dgrp", "gpio0egrp", "gpio0fgrp", "gpio0ggrp", "gpio0hgrp", "gpio0igrp", - "gpio0jgrp", "gpio0kgrp" }; + "gpio0jgrp", "gpio0kgrp", "gpio0lgrp", + "gpio0mgrp" }; static const char * const gpio1grps[] = { "gpio1agrp", "gpio1bgrp", "gpio1cgrp", "gpio1dgrp" }; static const char * const gpio2grps[] = { "gpio2agrp", "gpio2bgrp", "gpio2cgrp" }; -- cgit From 0b9335cbd38e3bd2025bcc23b5758df4ac035f75 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 20 Nov 2017 12:58:03 -0800 Subject: pinctrl: pxa: pxa2xx: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE This change resolves a new compile-time warning when built as a loadable module: WARNING: modpost: missing MODULE_LICENSE() in drivers/pinctrl/pxa/pinctrl-pxa2xx.o see include/linux/module.h for more information This adds the license as "GPL v2", which matches the header of the file. MODULE_DESCRIPTION and MODULE_AUTHOR are also added. Signed-off-by: Jesse Chan Signed-off-by: Linus Walleij --- drivers/pinctrl/pxa/pinctrl-pxa2xx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c index 866aa3ce1ac9..6cf0006d4c8d 100644 --- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c +++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c @@ -436,3 +436,7 @@ int pxa2xx_pinctrl_exit(struct platform_device *pdev) return 0; } EXPORT_SYMBOL_GPL(pxa2xx_pinctrl_exit); + +MODULE_AUTHOR("Robert Jarzmik "); +MODULE_DESCRIPTION("Marvell PXA2xx pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 13f9d59cef91a027bb338fc79b564fafa7680cd8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 23 Nov 2017 19:01:49 +0900 Subject: gpio: uniphier: fix mismatch between license text and MODULE_LICENSE The comment block of this file indicates GPL-2.0 "only", while the MODULE_LICENSE is GPL-2.0 "or later", as include/linux/module.h describes as follows: "GPL" [GNU Public License v2 or later] "GPL v2" [GNU Public License v2] I am the author of this driver, and my intention is GPL-2.0 "only". Fixes: dbe776c2ca54 ("gpio: uniphier: add UniPhier GPIO controller driver") Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/gpio/gpio-uniphier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 016d7427ebfa..761d8279abca 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -505,4 +505,4 @@ module_platform_driver(uniphier_gpio_driver); MODULE_AUTHOR("Masahiro Yamada "); MODULE_DESCRIPTION("UniPhier GPIO driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit From f5a26acf0162477af6ee4c11b4fb9cffe5d3e257 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 29 Nov 2017 16:25:44 +0300 Subject: pinctrl: intel: Initialize GPIO properly when used through irqchip When a GPIO is requested using gpiod_get_* APIs the intel pinctrl driver switches the pin to GPIO mode and makes sure interrupts are routed to the GPIO hardware instead of IOAPIC. However, if the GPIO is used directly through irqchip, as is the case with many I2C-HID devices where I2C core automatically configures interrupt for the device, the pin is not initialized as GPIO. Instead we rely that the BIOS configures the pin accordingly which seems not to be the case at least in Asus X540NA SKU3 with Focaltech touchpad. When the pin is not properly configured it might result weird behaviour like interrupts suddenly stop firing completely and the touchpad stops responding to user input. Fix this by properly initializing the pin to GPIO mode also when it is used directly through irqchip. Fixes: 7981c0015af2 ("pinctrl: intel: Add Intel Sunrisepoint pin controller and GPIO support") Reported-by: Daniel Drake Reported-and-tested-by: Chris Chiu Signed-off-by: Mika Westerberg Cc: stable@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-intel.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 4c2369a8d926..359800fcb951 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -425,6 +425,18 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) writel(value, padcfg0); } +static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) +{ + u32 value; + + /* Put the pad into GPIO mode */ + value = readl(padcfg0) & ~PADCFG0_PMODE_MASK; + /* Disable SCI/SMI/NMI generation */ + value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); + value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); + writel(value, padcfg0); +} + static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned pin) @@ -432,7 +444,6 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *padcfg0; unsigned long flags; - u32 value; raw_spin_lock_irqsave(&pctrl->lock, flags); @@ -442,13 +453,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, } padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); - /* Put the pad into GPIO mode */ - value = readl(padcfg0) & ~PADCFG0_PMODE_MASK; - /* Disable SCI/SMI/NMI generation */ - value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); - value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); - writel(value, padcfg0); - + intel_gpio_set_gpio_mode(padcfg0); /* Disable TX buffer and enable RX (this will be input) */ __intel_gpio_set_direction(padcfg0, true); @@ -968,6 +973,8 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) raw_spin_lock_irqsave(&pctrl->lock, flags); + intel_gpio_set_gpio_mode(reg); + value = readl(reg); value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); -- cgit From e7c0e2f372f4fefc06a5edb997cc20f58e73595e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 30 Nov 2017 09:46:48 +0100 Subject: pinctrl: stm32: Fix copyright Uniformize STMicroelectronics copyrights header Add SPDX identifier Signed-off-by: Benjamin Gaignard Acked-by: Alexandre TORGUE Acked-by: Maxime Coquelin Signed-off-by: Linus Walleij --- drivers/pinctrl/stm32/pinctrl-stm32.c | 3 ++- drivers/pinctrl/stm32/pinctrl-stm32.h | 3 ++- drivers/pinctrl/stm32/pinctrl-stm32f429.c | 3 ++- drivers/pinctrl/stm32/pinctrl-stm32f469.c | 6 +++--- drivers/pinctrl/stm32/pinctrl-stm32f746.c | 3 ++- drivers/pinctrl/stm32/pinctrl-stm32h743.c | 6 +++--- 6 files changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index a276c61be217..82bb617e8c61 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -1,7 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics 2017 * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 * * Heavily based on Mediatek's pinctrl driver */ diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h index 8702a9992ce5..473a6238a27b 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.h +++ b/drivers/pinctrl/stm32/pinctrl-stm32.h @@ -1,7 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics 2017 * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 */ #ifndef __PINCTRL_STM32_H #define __PINCTRL_STM32_H diff --git a/drivers/pinctrl/stm32/pinctrl-stm32f429.c b/drivers/pinctrl/stm32/pinctrl-stm32f429.c index 4bbade25acc6..663a97113c51 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32f429.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32f429.c @@ -1,7 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics 2017 * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 */ #include #include diff --git a/drivers/pinctrl/stm32/pinctrl-stm32f469.c b/drivers/pinctrl/stm32/pinctrl-stm32f469.c index 86c8cebfa9b9..ed5397f6d7f2 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32f469.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32f469.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) Alexandre Torgue 2016 - * Author: Alexandre Torgue - * License terms: GNU General Public License (GPL), version 2 + * Copyright (C) STMicroelectronics 2017 + * Author: Alexandre Torgue for STMicroelectronics. */ #include #include diff --git a/drivers/pinctrl/stm32/pinctrl-stm32f746.c b/drivers/pinctrl/stm32/pinctrl-stm32f746.c index a2fae7357c36..d832aab7ebe1 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32f746.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32f746.c @@ -1,7 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics 2017 * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 */ #include #include diff --git a/drivers/pinctrl/stm32/pinctrl-stm32h743.c b/drivers/pinctrl/stm32/pinctrl-stm32h743.c index e34b2b9217ce..ffe7b5271506 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32h743.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32h743.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) Alexandre Torgue 2017 - * Author: Alexandre Torgue - * License terms: GNU General Public License (GPL), version 2 + * Copyright (C) STMicroelectronics 2017 + * Author: Alexandre Torgue for STMicroelectronics. */ #include #include -- cgit From 14911c6f48ec9571343ac36ae02f2db68bf9e7f9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 28 Nov 2017 16:53:32 +0100 Subject: i2c: gpio: add fault injector Add fault injection capabilities to the i2c-gpio driver. When connected to another I2C bus, it can create unusual states which the other I2C bus master driver needs to handle. Only for debugging! Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 8 +++ drivers/i2c/busses/i2c-gpio.c | 111 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 009345d8f49d..a9805c7cb305 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -603,6 +603,14 @@ config I2C_GPIO This is a very simple bitbanging I2C driver utilizing the arch-neutral GPIO API to control the SCL and SDA lines. +config I2C_GPIO_FAULT_INJECTOR + bool "GPIO-based fault injector" + depends on I2C_GPIO + help + This adds some functionality to the i2c-gpio driver which can inject + faults to an I2C bus, so another bus master can be stress-tested. + This is for debugging. If unsure, say 'no'. + config I2C_HIGHLANDER tristate "Highlander FPGA SMBus interface" depends on SH_HIGHLANDER diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index d80ea6ce91bb..3312ef981cb7 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -7,6 +7,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include +#include #include #include #include @@ -23,6 +25,9 @@ struct i2c_gpio_private_data { struct i2c_adapter adap; struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR + struct dentry *debug_dir; +#endif }; /* @@ -64,6 +69,108 @@ static int i2c_gpio_getscl(void *data) return gpiod_get_value(priv->scl); } +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR +static struct dentry *i2c_gpio_debug_dir; + +#define setsda(bd, val) ((bd)->setsda((bd)->data, val)) +#define setscl(bd, val) ((bd)->setscl((bd)->data, val)) +#define getsda(bd) ((bd)->getsda((bd)->data)) +#define getscl(bd) ((bd)->getscl((bd)->data)) + +#define WIRE_ATTRIBUTE(wire) \ +static int fops_##wire##_get(void *data, u64 *val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_adapter(&priv->adap); \ + *val = get##wire(&priv->bit_data); \ + i2c_unlock_adapter(&priv->adap); \ + return 0; \ +} \ +static int fops_##wire##_set(void *data, u64 val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_adapter(&priv->adap); \ + set##wire(&priv->bit_data, val); \ + i2c_unlock_adapter(&priv->adap); \ + return 0; \ +} \ +DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") + +WIRE_ATTRIBUTE(scl); +WIRE_ATTRIBUTE(sda); + +static int fops_incomplete_transfer_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + struct i2c_algo_bit_data *bit_data = &priv->bit_data; + int i, pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */ + pattern = (addr << 2) | 3; + + i2c_lock_adapter(&priv->adap); + + /* START condition */ + setsda(bit_data, 0); + udelay(bit_data->udelay); + + /* Send ADDR+RD, request ACK, don't send STOP */ + for (i = 8; i >= 0; i--) { + setscl(bit_data, 0); + udelay(bit_data->udelay / 2); + setsda(bit_data, (pattern >> i) & 1); + udelay((bit_data->udelay + 1) / 2); + setscl(bit_data, 1); + udelay(bit_data->udelay); + } + + i2c_unlock_adapter(&priv->adap); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n"); + +static void i2c_gpio_fault_injector_init(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + /* + * If there will be a debugfs-dir per i2c adapter somewhen, put the + * 'fault-injector' dir there. Until then, we have a global dir with + * all adapters as subdirs. + */ + if (!i2c_gpio_debug_dir) { + i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); + if (!i2c_gpio_debug_dir) + return; + } + + priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); + if (!priv->debug_dir) + return; + + debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); + debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); + debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir, + priv, &fops_incomplete_transfer); +} + +static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + debugfs_remove_recursive(priv->debug_dir); +} +#else +static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} +static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} +#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ + static void of_i2c_gpio_get_props(struct device_node *np, struct i2c_gpio_platform_data *pdata) { @@ -228,6 +335,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) pdata->scl_is_output_only ? ", no clock stretching" : ""); + i2c_gpio_fault_injector_init(pdev); + return 0; } @@ -236,6 +345,8 @@ static int i2c_gpio_remove(struct platform_device *pdev) struct i2c_gpio_private_data *priv; struct i2c_adapter *adap; + i2c_gpio_fault_injector_exit(pdev); + priv = platform_get_drvdata(pdev); adap = &priv->adap; -- cgit From e94bc5d18be03dac8e9d73d30c5523728edeff76 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:02 +0100 Subject: i2c: add helpers to ease DMA handling One helper checks if DMA is suitable and optionally creates a bounce buffer, if not. The other function returns the bounce buffer and makes sure the data is properly copied back to the message. Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index bf52cca87363..b6ca97f0322b 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -2200,6 +2200,52 @@ void i2c_put_adapter(struct i2c_adapter *adap) } EXPORT_SYMBOL(i2c_put_adapter); +/** + * i2c_get_dma_safe_msg_buf() - get a DMA safe buffer for the given i2c_msg + * @msg: the message to be checked + * @threshold: the minimum number of bytes for which using DMA makes sense + * + * Return: NULL if a DMA safe buffer was not obtained. Use msg->buf with PIO. + * Or a valid pointer to be used with DMA. After use, release it by + * calling i2c_release_dma_safe_msg_buf(). + * + * This function must only be called from process context! + */ +u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold) +{ + if (msg->len < threshold) + return NULL; + + if (msg->flags & I2C_M_DMA_SAFE) + return msg->buf; + + pr_debug("using bounce buffer for addr=0x%02x, len=%d\n", + msg->addr, msg->len); + + if (msg->flags & I2C_M_RD) + return kzalloc(msg->len, GFP_KERNEL); + else + return kmemdup(msg->buf, msg->len, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf); + +/** + * i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg + * @msg: the message to be synced with + * @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL. + */ +void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf) +{ + if (!buf || buf == msg->buf) + return; + + if (msg->flags & I2C_M_RD) + memcpy(msg->buf, buf, msg->len); + + kfree(buf); +} +EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf); + MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_LICENSE("GPL"); -- cgit From 978336d48d887d6deb7793e0d20a4673f357fb8e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:03 +0100 Subject: i2c: dev: mark RDWR buffers as DMA_SAFE Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 2cab27a68479..036a03f0d0a6 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -264,6 +264,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, res = PTR_ERR(msgs[i].buf); break; } + /* memdup_user allocates with GFP_KERNEL, so DMA is ok */ + msgs[i].flags |= I2C_M_DMA_SAFE; /* * If the message length is received from the slave (similar -- cgit From 8a91732b3b33454d8034e7be5c8342f028ea772e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:04 +0100 Subject: i2c: refactor i2c_master_{send_recv} Those two functions are very similar, the only differences are that one needs the I2C_M_RD flag for its message while the other one needs the buffer casted to drop the const. Introduce a generic helper which allows to specify the flags (also needed later for DMA safe variants of these calls) and let the casting be done in the inlining functions which are now calling the new helper function. Signed-off-by: Wolfram Sang Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 64 +++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index b6ca97f0322b..bb34a5d41133 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1911,63 +1911,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) EXPORT_SYMBOL(i2c_transfer); /** - * i2c_master_send - issue a single I2C message in master transmit mode + * i2c_transfer_buffer_flags - issue a single I2C message transferring data + * to/from a buffer * @client: Handle to slave device - * @buf: Data that will be written to the slave - * @count: How many bytes to write, must be less than 64k since msg.len is u16 + * @buf: Where the data is stored + * @count: How many bytes to transfer, must be less than 64k since msg.len is u16 + * @flags: The flags to be used for the message, e.g. I2C_M_RD for reads * - * Returns negative errno, or else the number of bytes written. + * Returns negative errno, or else the number of bytes transferred. */ -int i2c_master_send(const struct i2c_client *client, const char *buf, int count) +int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, + int count, u16 flags) { int ret; - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.len = count; - msg.buf = (char *)buf; - - ret = i2c_transfer(adap, &msg, 1); - - /* - * If everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1) ? count : ret; -} -EXPORT_SYMBOL(i2c_master_send); - -/** - * i2c_master_recv - issue a single I2C message in master receive mode - * @client: Handle to slave device - * @buf: Where to store data read from slave - * @count: How many bytes to read, must be less than 64k since msg.len is u16 - * - * Returns negative errno, or else the number of bytes read. - */ -int i2c_master_recv(const struct i2c_client *client, char *buf, int count) -{ - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - int ret; - - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.flags |= I2C_M_RD; - msg.len = count; - msg.buf = buf; + struct i2c_msg msg = { + .addr = client->addr, + .flags = flags | (client->flags & I2C_M_TEN), + .len = count, + .buf = buf, + }; - ret = i2c_transfer(adap, &msg, 1); + ret = i2c_transfer(client->adapter, &msg, 1); /* - * If everything went ok (i.e. 1 msg received), return #bytes received, - * else error code. + * If everything went ok (i.e. 1 msg transferred), return #bytes + * transferred, else error code. */ return (ret == 1) ? count : ret; } -EXPORT_SYMBOL(i2c_master_recv); +EXPORT_SYMBOL(i2c_transfer_buffer_flags); /* ---------------------------------------------------- * the i2c address scanning function -- cgit From 8a77821e74d6d5ba2eacd4b450684ae6cbe012a0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:06 +0100 Subject: i2c: smbus: use DMA safe buffers for emulated SMBus transactions For all block commands, try to allocate a DMA safe buffer and mark it accordingly. Only use the stack, if the buffers cannot be allocated. Signed-off-by: Wolfram Sang Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-smbus.c | 45 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 4bb9927afd01..1238c94fe5a1 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -18,6 +18,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -291,6 +292,22 @@ s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, } EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); +static void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val) +{ + bool is_read = msg->flags & I2C_M_RD; + unsigned char *dma_buf; + + dma_buf = kzalloc(I2C_SMBUS_BLOCK_MAX + (is_read ? 2 : 3), GFP_KERNEL); + if (!dma_buf) + return; + + msg->buf = dma_buf; + msg->flags |= I2C_M_DMA_SAFE; + + if (init_val) + msg->buf[0] = init_val; +} + /* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, @@ -368,6 +385,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ + i2c_smbus_try_get_dmabuf(&msg[1], 0); } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { @@ -376,8 +394,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i < msg[0].len; i++) - msgbuf0[i] = data->block[i-1]; + msg[0].buf[i] = data->block[i - 1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: @@ -389,16 +409,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + msg[0].len = data->block[0] + 2; + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i < msg[0].len; i++) - msgbuf0[i] = data->block[i-1]; + msg[0].buf[i] = data->block[i - 1]; + msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ + i2c_smbus_try_get_dmabuf(&msg[1], 0); break; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = data->block[0]; + i2c_smbus_try_get_dmabuf(&msg[1], 0); } else { msg[0].len = data->block[0] + 1; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { @@ -407,8 +432,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i <= data->block[0]; i++) - msgbuf0[i] = data->block[i]; + msg[0].buf[i] = data->block[i]; } break; default: @@ -456,14 +483,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: for (i = 0; i < data->block[0]; i++) - data->block[i+1] = msgbuf1[i]; + data->block[i + 1] = msg[1].buf[i]; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: - for (i = 0; i < msgbuf1[0] + 1; i++) - data->block[i] = msgbuf1[i]; + for (i = 0; i < msg[1].buf[0] + 1; i++) + data->block[i] = msg[1].buf[i]; break; } + + if (msg[0].flags & I2C_M_DMA_SAFE) + kfree(msg[0].buf); + if (msg[1].flags & I2C_M_DMA_SAFE) + kfree(msg[1].buf); + return 0; } -- cgit From fe23aa9a1670b8800b251fc0400425e765c81880 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:08 +0100 Subject: i2c: sh_mobile: use core helper to decide when to use DMA This ensures that we fall back to PIO if the message length is too small for DMA being useful. Otherwise, we use DMA. A bounce buffer might be applied by the helper if the original message buffer is not DMA safe. Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index bc1605a31534..b01607b4fce2 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -144,6 +144,7 @@ struct sh_mobile_i2c_data { struct dma_chan *dma_rx; struct scatterlist sg; enum dma_data_direction dma_direction; + u8 *dma_buf; }; struct sh_mobile_dt_config { @@ -501,6 +502,8 @@ static void sh_mobile_i2c_dma_callback(void *data) pd->pos = pd->msg->len; pd->stop_after_dma = true; + i2c_release_dma_safe_msg_buf(pd->msg, pd->dma_buf); + iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); } @@ -561,7 +564,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) if (IS_ERR(chan)) return; - dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir); + dma_addr = dma_map_single(chan->device->dev, pd->dma_buf, pd->msg->len, dir); if (dma_mapping_error(chan->device->dev, dma_addr)) { dev_dbg(pd->dev, "dma map failed, using PIO\n"); return; @@ -618,7 +621,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, pd->pos = -1; pd->sr = 0; - if (pd->msg->len > 8) + pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8); + if (pd->dma_buf) sh_mobile_i2c_xfer_dma(pd); /* Enable all interrupts to begin with */ -- cgit From adbd77b589d0345cfc42f1ae0b3414e62a2bf866 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:09 +0100 Subject: i2c: rcar: skip DMA if buffer is not safe This HW is prone to races, so it needs to setup new messages in irq context. That means we can't alloc bounce buffers if a message buffer is not DMA safe. So, in that case, simply fall back to PIO. Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 15d764afec3b..8a2ae3e6c561 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -359,7 +359,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) int len; /* Do not use DMA if it's not available or for messages < 8 bytes */ - if (IS_ERR(chan) || msg->len < 8) + if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE)) return; if (read) { -- cgit From f0200c02883367f0eb6c9e2f19a8ab6335a52b86 Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Tue, 30 Aug 2016 22:44:51 +0530 Subject: ps3: Remove deprecated create_singlethread_workqueue The workqueue "ps3av->wq" queues a single work item &ps3av->work and hence doesn't require ordering. It is involved in waking up ps3avd to do the video mode setting and hence it's not being used on a memory reclaim path. Hence, it has been converted to use system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. The work item has been flushed in ps3av_remove to ensure that there are no pending tasks while disconnecting the driver. Signed-off-by: Bhaktipriya Shridhar Acked-by: Tejun Heo Signed-off-by: Michael Ellerman --- drivers/ps3/ps3av.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 437fc35beb7b..e293606b0334 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -44,7 +44,6 @@ static struct ps3av { struct mutex mutex; struct work_struct work; struct completion done; - struct workqueue_struct *wq; int open_count; struct ps3_system_bus_device *dev; @@ -485,7 +484,7 @@ static int ps3av_set_videomode(void) ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); /* wake up ps3avd to do the actual video mode setting */ - queue_work(ps3av->wq, &ps3av->work); + schedule_work(&ps3av->work); return 0; } @@ -956,11 +955,6 @@ static int ps3av_probe(struct ps3_system_bus_device *dev) INIT_WORK(&ps3av->work, ps3avd); init_completion(&ps3av->done); complete(&ps3av->done); - ps3av->wq = create_singlethread_workqueue("ps3avd"); - if (!ps3av->wq) { - res = -ENOMEM; - goto fail; - } switch (ps3_os_area_get_av_multi_out()) { case PS3_PARAM_AV_MULTI_OUT_NTSC: @@ -1018,8 +1012,7 @@ static int ps3av_remove(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); if (ps3av) { ps3av_cmd_fin(); - if (ps3av->wq) - destroy_workqueue(ps3av->wq); + flush_work(&ps3av->work); kfree(ps3av); ps3av = NULL; } -- cgit From b92ac66a1819602b1427ac72d4a70c10ba7640ad Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 10 Nov 2017 20:59:01 +0300 Subject: pinctrl: sh-pfc: Add R8A77970 PFC support Add the PFC support for the R8A77970 SoC including pin groups for some on-chip devices such as CAN-FD, [H]SCIF, I2C, INTC-EX, MMC, MSIOF, PWM, VIN... Based on the original (and large) patch by Daisuke Matsushita . Signed-off-by: Vladimir Barinov Signed-off-by: Sergei Shtylyov Acked-by: Rob Herring [geert: Drop EtherAVB for now] Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/Kconfig | 5 + drivers/pinctrl/sh-pfc/Makefile | 1 + drivers/pinctrl/sh-pfc/core.c | 6 + drivers/pinctrl/sh-pfc/pfc-r8a77970.c | 2329 +++++++++++++++++++++++++++++++++ drivers/pinctrl/sh-pfc/sh_pfc.h | 1 + 5 files changed, 2342 insertions(+) create mode 100644 drivers/pinctrl/sh-pfc/pfc-r8a77970.c (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig index 5d5312eb7102..4ed3761418f9 100644 --- a/drivers/pinctrl/sh-pfc/Kconfig +++ b/drivers/pinctrl/sh-pfc/Kconfig @@ -89,6 +89,11 @@ config PINCTRL_PFC_R8A7796 depends on ARCH_R8A7796 select PINCTRL_SH_PFC +config PINCTRL_PFC_R8A77970 + def_bool y + depends on ARCH_R8A77970 + select PINCTRL_SH_PFC + config PINCTRL_PFC_R8A77995 def_bool y depends on ARCH_R8A77995 diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile index a7903904b64e..22e758ce1fc2 100644 --- a/drivers/pinctrl/sh-pfc/Makefile +++ b/drivers/pinctrl/sh-pfc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PINCTRL_PFC_R8A7794) += pfc-r8a7794.o obj-$(CONFIG_PINCTRL_PFC_R8A7795) += pfc-r8a7795.o obj-$(CONFIG_PINCTRL_PFC_R8A7795) += pfc-r8a7795-es1.o obj-$(CONFIG_PINCTRL_PFC_R8A7796) += pfc-r8a7796.o +obj-$(CONFIG_PINCTRL_PFC_R8A77970) += pfc-r8a77970.o obj-$(CONFIG_PINCTRL_PFC_R8A77995) += pfc-r8a77995.o obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index cf4ae4bc9115..e9eb7a7c6fac 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -557,6 +557,12 @@ static const struct of_device_id sh_pfc_of_table[] = { .data = &r8a7796_pinmux_info, }, #endif +#ifdef CONFIG_PINCTRL_PFC_R8A77970 + { + .compatible = "renesas,pfc-r8a77970", + .data = &r8a77970_pinmux_info, + }, +#endif #ifdef CONFIG_PINCTRL_PFC_R8A77995 { .compatible = "renesas,pfc-r8a77995", diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c new file mode 100644 index 000000000000..794f12d74449 --- /dev/null +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c @@ -0,0 +1,2329 @@ +/* + * R8A77970 processor support - PFC hardware block. + * + * Copyright (C) 2016 Renesas Electronics Corp. + * Copyright (C) 2017 Cogent Embedded, Inc. + * + * This file is based on the drivers/pinctrl/sh-pfc/pfc-r8a7795.c + * + * R-Car Gen3 processor support - PFC hardware block. + * + * Copyright (C) 2015 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include +#include + +#include "core.h" +#include "sh_pfc.h" + +#define CPU_ALL_PORT(fn, sfx) \ + PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PORT_GP_CFG_28(1, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PORT_GP_CFG_17(2, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PORT_GP_CFG_6(4, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PORT_GP_CFG_15(5, fn, sfx, SH_PFC_PIN_CFG_DRIVE_STRENGTH) +/* + * F_() : just information + * FM() : macro for FN_xxx / xxx_MARK + */ + +/* GPSR0 */ +#define GPSR0_21 F_(DU_EXODDF_DU_ODDF_DISP_CDE, IP2_23_20) +#define GPSR0_20 F_(DU_EXVSYNC_DU_VSYNC, IP2_19_16) +#define GPSR0_19 F_(DU_EXHSYNC_DU_HSYNC, IP2_15_12) +#define GPSR0_18 F_(DU_DOTCLKOUT, IP2_11_8) +#define GPSR0_17 F_(DU_DB7, IP2_7_4) +#define GPSR0_16 F_(DU_DB6, IP2_3_0) +#define GPSR0_15 F_(DU_DB5, IP1_31_28) +#define GPSR0_14 F_(DU_DB4, IP1_27_24) +#define GPSR0_13 F_(DU_DB3, IP1_23_20) +#define GPSR0_12 F_(DU_DB2, IP1_19_16) +#define GPSR0_11 F_(DU_DG7, IP1_15_12) +#define GPSR0_10 F_(DU_DG6, IP1_11_8) +#define GPSR0_9 F_(DU_DG5, IP1_7_4) +#define GPSR0_8 F_(DU_DG4, IP1_3_0) +#define GPSR0_7 F_(DU_DG3, IP0_31_28) +#define GPSR0_6 F_(DU_DG2, IP0_27_24) +#define GPSR0_5 F_(DU_DR7, IP0_23_20) +#define GPSR0_4 F_(DU_DR6, IP0_19_16) +#define GPSR0_3 F_(DU_DR5, IP0_15_12) +#define GPSR0_2 F_(DU_DR4, IP0_11_8) +#define GPSR0_1 F_(DU_DR3, IP0_7_4) +#define GPSR0_0 F_(DU_DR2, IP0_3_0) + +/* GPSR1 */ +#define GPSR1_27 F_(DIGRF_CLKOUT, IP8_27_24) +#define GPSR1_26 F_(DIGRF_CLKIN, IP8_23_20) +#define GPSR1_25 F_(CANFD_CLK_A, IP8_19_16) +#define GPSR1_24 F_(CANFD1_RX, IP8_15_12) +#define GPSR1_23 F_(CANFD1_TX, IP8_11_8) +#define GPSR1_22 F_(CANFD0_RX_A, IP8_7_4) +#define GPSR1_21 F_(CANFD0_TX_A, IP8_3_0) +#define GPSR1_20 F_(AVB0_AVTP_CAPTURE, IP7_31_28) +#define GPSR1_19 FM(AVB0_AVTP_MATCH) +#define GPSR1_18 FM(AVB0_LINK) +#define GPSR1_17 FM(AVB0_PHY_INT) +#define GPSR1_16 FM(AVB0_MAGIC) +#define GPSR1_15 FM(AVB0_MDC) +#define GPSR1_14 FM(AVB0_MDIO) +#define GPSR1_13 FM(AVB0_TXCREFCLK) +#define GPSR1_12 FM(AVB0_TD3) +#define GPSR1_11 FM(AVB0_TD2) +#define GPSR1_10 FM(AVB0_TD1) +#define GPSR1_9 FM(AVB0_TD0) +#define GPSR1_8 FM(AVB0_TXC) +#define GPSR1_7 FM(AVB0_TX_CTL) +#define GPSR1_6 FM(AVB0_RD3) +#define GPSR1_5 FM(AVB0_RD2) +#define GPSR1_4 FM(AVB0_RD1) +#define GPSR1_3 FM(AVB0_RD0) +#define GPSR1_2 FM(AVB0_RXC) +#define GPSR1_1 FM(AVB0_RX_CTL) +#define GPSR1_0 F_(IRQ0, IP2_27_24) + +/* GPSR2 */ +#define GPSR2_16 F_(VI0_FIELD, IP4_31_28) +#define GPSR2_15 F_(VI0_DATA11, IP4_27_24) +#define GPSR2_14 F_(VI0_DATA10, IP4_23_20) +#define GPSR2_13 F_(VI0_DATA9, IP4_19_16) +#define GPSR2_12 F_(VI0_DATA8, IP4_15_12) +#define GPSR2_11 F_(VI0_DATA7, IP4_11_8) +#define GPSR2_10 F_(VI0_DATA6, IP4_7_4) +#define GPSR2_9 F_(VI0_DATA5, IP4_3_0) +#define GPSR2_8 F_(VI0_DATA4, IP3_31_28) +#define GPSR2_7 F_(VI0_DATA3, IP3_27_24) +#define GPSR2_6 F_(VI0_DATA2, IP3_23_20) +#define GPSR2_5 F_(VI0_DATA1, IP3_19_16) +#define GPSR2_4 F_(VI0_DATA0, IP3_15_12) +#define GPSR2_3 F_(VI0_VSYNC_N, IP3_11_8) +#define GPSR2_2 F_(VI0_HSYNC_N, IP3_7_4) +#define GPSR2_1 F_(VI0_CLKENB, IP3_3_0) +#define GPSR2_0 F_(VI0_CLK, IP2_31_28) + +/* GPSR3 */ +#define GPSR3_16 F_(VI1_FIELD, IP7_3_0) +#define GPSR3_15 F_(VI1_DATA11, IP6_31_28) +#define GPSR3_14 F_(VI1_DATA10, IP6_27_24) +#define GPSR3_13 F_(VI1_DATA9, IP6_23_20) +#define GPSR3_12 F_(VI1_DATA8, IP6_19_16) +#define GPSR3_11 F_(VI1_DATA7, IP6_15_12) +#define GPSR3_10 F_(VI1_DATA6, IP6_11_8) +#define GPSR3_9 F_(VI1_DATA5, IP6_7_4) +#define GPSR3_8 F_(VI1_DATA4, IP6_3_0) +#define GPSR3_7 F_(VI1_DATA3, IP5_31_28) +#define GPSR3_6 F_(VI1_DATA2, IP5_27_24) +#define GPSR3_5 F_(VI1_DATA1, IP5_23_20) +#define GPSR3_4 F_(VI1_DATA0, IP5_19_16) +#define GPSR3_3 F_(VI1_VSYNC_N, IP5_15_12) +#define GPSR3_2 F_(VI1_HSYNC_N, IP5_11_8) +#define GPSR3_1 F_(VI1_CLKENB, IP5_7_4) +#define GPSR3_0 F_(VI1_CLK, IP5_3_0) + +/* GPSR4 */ +#define GPSR4_5 F_(SDA2, IP7_27_24) +#define GPSR4_4 F_(SCL2, IP7_23_20) +#define GPSR4_3 F_(SDA1, IP7_19_16) +#define GPSR4_2 F_(SCL1, IP7_15_12) +#define GPSR4_1 F_(SDA0, IP7_11_8) +#define GPSR4_0 F_(SCL0, IP7_7_4) + +/* GPSR5 */ +#define GPSR5_14 FM(RPC_INT_N) +#define GPSR5_13 FM(RPC_WP_N) +#define GPSR5_12 FM(RPC_RESET_N) +#define GPSR5_11 FM(QSPI1_SSL) +#define GPSR5_10 FM(QSPI1_IO3) +#define GPSR5_9 FM(QSPI1_IO2) +#define GPSR5_8 FM(QSPI1_MISO_IO1) +#define GPSR5_7 FM(QSPI1_MOSI_IO0) +#define GPSR5_6 FM(QSPI1_SPCLK) +#define GPSR5_5 FM(QSPI0_SSL) +#define GPSR5_4 FM(QSPI0_IO3) +#define GPSR5_3 FM(QSPI0_IO2) +#define GPSR5_2 FM(QSPI0_MISO_IO1) +#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) +#define IP0_11_8 FM(DU_DR4) FM(HCTS0_N) F_(0, 0) FM(A2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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_15_12 FM(DU_DR5) FM(HTX0) F_(0, 0) FM(A3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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_19_16 FM(DU_DR6) FM(MSIOF3_RXD) F_(0, 0) FM(A4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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_23_20 FM(DU_DR7) FM(MSIOF3_TXD) F_(0, 0) FM(A5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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_27_24 FM(DU_DG2) FM(MSIOF3_SS1) F_(0, 0) FM(A6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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_31_28 FM(DU_DG3) FM(MSIOF3_SS2) F_(0, 0) FM(A7) FM(PWMFSW0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1_3_0 FM(DU_DG4) F_(0, 0) F_(0, 0) FM(A8) FM(FSO_CFE_0_N_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) +#define IP1_7_4 FM(DU_DG5) F_(0, 0) F_(0, 0) FM(A9) FM(FSO_CFE_1_N_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) +#define IP1_11_8 FM(DU_DG6) F_(0, 0) F_(0, 0) FM(A10) FM(FSO_TOE_N_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) +#define IP1_15_12 FM(DU_DG7) F_(0, 0) F_(0, 0) FM(A11) FM(IRQ1) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1_19_16 FM(DU_DB2) F_(0, 0) F_(0, 0) FM(A12) FM(IRQ2) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1_23_20 FM(DU_DB3) F_(0, 0) F_(0, 0) FM(A13) FM(FXR_CLKOUT1) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1_27_24 FM(DU_DB4) F_(0, 0) F_(0, 0) FM(A14) FM(FXR_CLKOUT2) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1_31_28 FM(DU_DB5) F_(0, 0) F_(0, 0) FM(A15) FM(FXR_TXENA_N) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2_3_0 FM(DU_DB6) F_(0, 0) F_(0, 0) FM(A16) FM(FXR_TXENB_N) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2_7_4 FM(DU_DB7) F_(0, 0) F_(0, 0) FM(A17) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2_11_8 FM(DU_DOTCLKOUT) FM(SCIF_CLK_A) F_(0, 0) FM(A18) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2_15_12 FM(DU_EXHSYNC_DU_HSYNC) FM(HRX0) F_(0, 0) FM(A19) FM(IRQ3) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2_19_16 FM(DU_EXVSYNC_DU_VSYNC) FM(MSIOF3_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2_23_20 FM(DU_EXODDF_DU_ODDF_DISP_CDE) FM(MSIOF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2_27_24 FM(IRQ0) 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) F_(0, 0) +#define IP2_31_28 FM(VI0_CLK) FM(MSIOF2_SCK) FM(SCK3) F_(0, 0) FM(HSCK3) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP3_3_0 FM(VI0_CLKENB) FM(MSIOF2_RXD) FM(RX3) FM(RD_WR_N) FM(HCTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP3_7_4 FM(VI0_HSYNC_N) FM(MSIOF2_TXD) FM(TX3) F_(0, 0) FM(HRTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP3_11_8 FM(VI0_VSYNC_N) FM(MSIOF2_SYNC) FM(CTS3_N) F_(0, 0) FM(HTX3) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP3_15_12 FM(VI0_DATA0) FM(MSIOF2_SS1) FM(RTS3_N_TANS) F_(0, 0) FM(HRX3) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP3_19_16 FM(VI0_DATA1) FM(MSIOF2_SS2) FM(SCK1) F_(0, 0) FM(SPEEDIN_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) +#define IP3_23_20 FM(VI0_DATA2) FM(AVB0_AVTP_PPS) FM(SDA3_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) F_(0, 0) +#define IP3_27_24 FM(VI0_DATA3) FM(HSCK1) FM(SCL3_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) F_(0, 0) +#define IP3_31_28 FM(VI0_DATA4) FM(HRTS1_N) FM(RX1_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) F_(0, 0) +#define IP4_3_0 FM(VI0_DATA5) FM(HCTS1_N) FM(TX1_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) F_(0, 0) +#define IP4_7_4 FM(VI0_DATA6) FM(HTX1) FM(CTS1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP4_11_8 FM(VI0_DATA7) FM(HRX1) FM(RTS1_N_TANS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP4_15_12 FM(VI0_DATA8) FM(HSCK2) FM(PWM0_A) FM(A22) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP4_19_16 FM(VI0_DATA9) FM(HCTS2_N) FM(PWM1_A) FM(A23) FM(FSO_CFE_0_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) +#define IP4_23_20 FM(VI0_DATA10) FM(HRTS2_N) FM(PWM2_A) FM(A24) FM(FSO_CFE_1_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) +#define IP4_27_24 FM(VI0_DATA11) FM(HTX2) FM(PWM3_A) FM(A25) FM(FSO_TOE_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) +#define IP4_31_28 FM(VI0_FIELD) FM(HRX2) FM(PWM4_A) FM(CS1_N) FM(FSCLKST2_N_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) +#define IP5_3_0 FM(VI1_CLK) FM(MSIOF1_RXD) F_(0, 0) FM(CS0_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP5_7_4 FM(VI1_CLKENB) FM(MSIOF1_TXD) F_(0, 0) FM(D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP5_11_8 FM(VI1_HSYNC_N) FM(MSIOF1_SCK) F_(0, 0) FM(D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP5_15_12 FM(VI1_VSYNC_N) FM(MSIOF1_SYNC) F_(0, 0) FM(D2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP5_19_16 FM(VI1_DATA0) FM(MSIOF1_SS1) F_(0, 0) FM(D3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP5_23_20 FM(VI1_DATA1) FM(MSIOF1_SS2) F_(0, 0) FM(D4) FM(MMC_CMD) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP5_27_24 FM(VI1_DATA2) FM(CANFD0_TX_B) F_(0, 0) FM(D5) FM(MMC_D0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP5_31_28 FM(VI1_DATA3) FM(CANFD0_RX_B) F_(0, 0) FM(D6) FM(MMC_D1) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP6_3_0 FM(VI1_DATA4) FM(CANFD_CLK_B) F_(0, 0) FM(D7) FM(MMC_D2) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP6_7_4 FM(VI1_DATA5) F_(0,0) FM(SCK4) FM(D8) FM(MMC_D3) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP6_11_8 FM(VI1_DATA6) F_(0,0) FM(RX4) FM(D9) FM(MMC_CLK) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP6_15_12 FM(VI1_DATA7) F_(0,0) FM(TX4) FM(D10) FM(MMC_D4) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP6_19_16 FM(VI1_DATA8) F_(0,0) FM(CTS4_N) FM(D11) FM(MMC_D5) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP6_23_20 FM(VI1_DATA9) F_(0,0) FM(RTS4_N_TANS) FM(D12) FM(MMC_D6) FM(SCL3_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) +#define IP6_27_24 FM(VI1_DATA10) F_(0,0) F_(0, 0) FM(D13) FM(MMC_D7) FM(SDA3_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) +#define IP6_31_28 FM(VI1_DATA11) FM(SCL4) FM(IRQ4) FM(D14) FM(MMC_WP) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP7_3_0 FM(VI1_FIELD) FM(SDA4) FM(IRQ5) FM(D15) FM(MMC_CD) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP7_7_4 FM(SCL0) FM(DU_DR0) FM(TPU0TO0) FM(CLKOUT) F_(0, 0) FM(MSIOF0_RXD) F_(0, 0) F_(0, 0) 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 IP7_11_8 FM(SDA0) FM(DU_DR1) FM(TPU0TO1) FM(BS_N) FM(SCK0) FM(MSIOF0_TXD) F_(0, 0) F_(0, 0) 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 IP7_15_12 FM(SCL1) FM(DU_DG0) FM(TPU0TO2) FM(RD_N) FM(CTS0_N) FM(MSIOF0_SCK) F_(0, 0) F_(0, 0) 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 IP7_19_16 FM(SDA1) FM(DU_DG1) FM(TPU0TO3) FM(WE0_N) FM(RTS0_N_TANS) FM(MSIOF0_SYNC) F_(0, 0) F_(0, 0) 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 IP7_23_20 FM(SCL2) FM(DU_DB0) FM(TCLK1_A) FM(WE1_N) FM(RX0) FM(MSIOF0_SS1) F_(0, 0) F_(0, 0) 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 IP7_27_24 FM(SDA2) FM(DU_DB1) FM(TCLK2_A) FM(EX_WAIT0) FM(TX0) FM(MSIOF0_SS2) F_(0, 0) F_(0, 0) 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 IP7_31_28 FM(AVB0_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) FM(FSCLKST2_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) +#define IP8_3_0 FM(CANFD0_TX_A) FM(FXR_TXDA) FM(PWM0_B) FM(DU_DISP) FM(FSCLKST2_N_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) +#define IP8_7_4 FM(CANFD0_RX_A) FM(RXDA_EXTFXR) FM(PWM1_B) FM(DU_CDE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP8_11_8 FM(CANFD1_TX) FM(FXR_TXDB) FM(PWM2_B) FM(TCLK1_B) FM(TX1_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) +#define IP8_15_12 FM(CANFD1_RX) FM(RXDB_EXTFXR) FM(PWM3_B) FM(TCLK2_B) FM(RX1_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) +#define IP8_19_16 FM(CANFD_CLK_A) FM(CLK_EXTFXR) FM(PWM4_B) FM(SPEEDIN_B) FM(SCIF_CLK_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) +#define IP8_23_20 FM(DIGRF_CLKIN) FM(DIGRF_CLKEN_IN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP8_27_24 FM(DIGRF_CLKOUT) FM(DIGRF_CLKEN_OUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP8_31_28 F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 PINMUX_GPSR \ +\ + GPSR1_27 \ + GPSR1_26 \ + GPSR1_25 \ + GPSR1_24 \ + GPSR1_23 \ + GPSR1_22 \ +GPSR0_21 GPSR1_21 \ +GPSR0_20 GPSR1_20 \ +GPSR0_19 GPSR1_19 \ +GPSR0_18 GPSR1_18 \ +GPSR0_17 GPSR1_17 \ +GPSR0_16 GPSR1_16 GPSR2_16 GPSR3_16 \ +GPSR0_15 GPSR1_15 GPSR2_15 GPSR3_15 \ +GPSR0_14 GPSR1_14 GPSR2_14 GPSR3_14 GPSR5_14 \ +GPSR0_13 GPSR1_13 GPSR2_13 GPSR3_13 GPSR5_13 \ +GPSR0_12 GPSR1_12 GPSR2_12 GPSR3_12 GPSR5_12 \ +GPSR0_11 GPSR1_11 GPSR2_11 GPSR3_11 GPSR5_11 \ +GPSR0_10 GPSR1_10 GPSR2_10 GPSR3_10 GPSR5_10 \ +GPSR0_9 GPSR1_9 GPSR2_9 GPSR3_9 GPSR5_9 \ +GPSR0_8 GPSR1_8 GPSR2_8 GPSR3_8 GPSR5_8 \ +GPSR0_7 GPSR1_7 GPSR2_7 GPSR3_7 GPSR5_7 \ +GPSR0_6 GPSR1_6 GPSR2_6 GPSR3_6 GPSR5_6 \ +GPSR0_5 GPSR1_5 GPSR2_5 GPSR3_5 GPSR4_5 GPSR5_5 \ +GPSR0_4 GPSR1_4 GPSR2_4 GPSR3_4 GPSR4_4 GPSR5_4 \ +GPSR0_3 GPSR1_3 GPSR2_3 GPSR3_3 GPSR4_3 GPSR5_3 \ +GPSR0_2 GPSR1_2 GPSR2_2 GPSR3_2 GPSR4_2 GPSR5_2 \ +GPSR0_1 GPSR1_1 GPSR2_1 GPSR3_1 GPSR4_1 GPSR5_1 \ +GPSR0_0 GPSR1_0 GPSR2_0 GPSR3_0 GPSR4_0 GPSR5_0 + +#define PINMUX_IPSR \ +\ +FM(IP0_3_0) IP0_3_0 FM(IP1_3_0) IP1_3_0 FM(IP2_3_0) IP2_3_0 FM(IP3_3_0) IP3_3_0 \ +FM(IP0_7_4) IP0_7_4 FM(IP1_7_4) IP1_7_4 FM(IP2_7_4) IP2_7_4 FM(IP3_7_4) IP3_7_4 \ +FM(IP0_11_8) IP0_11_8 FM(IP1_11_8) IP1_11_8 FM(IP2_11_8) IP2_11_8 FM(IP3_11_8) IP3_11_8 \ +FM(IP0_15_12) IP0_15_12 FM(IP1_15_12) IP1_15_12 FM(IP2_15_12) IP2_15_12 FM(IP3_15_12) IP3_15_12 \ +FM(IP0_19_16) IP0_19_16 FM(IP1_19_16) IP1_19_16 FM(IP2_19_16) IP2_19_16 FM(IP3_19_16) IP3_19_16 \ +FM(IP0_23_20) IP0_23_20 FM(IP1_23_20) IP1_23_20 FM(IP2_23_20) IP2_23_20 FM(IP3_23_20) IP3_23_20 \ +FM(IP0_27_24) IP0_27_24 FM(IP1_27_24) IP1_27_24 FM(IP2_27_24) IP2_27_24 FM(IP3_27_24) IP3_27_24 \ +FM(IP0_31_28) IP0_31_28 FM(IP1_31_28) IP1_31_28 FM(IP2_31_28) IP2_31_28 FM(IP3_31_28) IP3_31_28 \ +\ +FM(IP4_3_0) IP4_3_0 FM(IP5_3_0) IP5_3_0 FM(IP6_3_0) IP6_3_0 FM(IP7_3_0) IP7_3_0 \ +FM(IP4_7_4) IP4_7_4 FM(IP5_7_4) IP5_7_4 FM(IP6_7_4) IP6_7_4 FM(IP7_7_4) IP7_7_4 \ +FM(IP4_11_8) IP4_11_8 FM(IP5_11_8) IP5_11_8 FM(IP6_11_8) IP6_11_8 FM(IP7_11_8) IP7_11_8 \ +FM(IP4_15_12) IP4_15_12 FM(IP5_15_12) IP5_15_12 FM(IP6_15_12) IP6_15_12 FM(IP7_15_12) IP7_15_12 \ +FM(IP4_19_16) IP4_19_16 FM(IP5_19_16) IP5_19_16 FM(IP6_19_16) IP6_19_16 FM(IP7_19_16) IP7_19_16 \ +FM(IP4_23_20) IP4_23_20 FM(IP5_23_20) IP5_23_20 FM(IP6_23_20) IP6_23_20 FM(IP7_23_20) IP7_23_20 \ +FM(IP4_27_24) IP4_27_24 FM(IP5_27_24) IP5_27_24 FM(IP6_27_24) IP6_27_24 FM(IP7_27_24) IP7_27_24 \ +FM(IP4_31_28) IP4_31_28 FM(IP5_31_28) IP5_31_28 FM(IP6_31_28) IP6_31_28 FM(IP7_31_28) IP7_31_28 \ +\ +FM(IP8_3_0) IP8_3_0 \ +FM(IP8_7_4) IP8_7_4 \ +FM(IP8_11_8) IP8_11_8 \ +FM(IP8_15_12) IP8_15_12 \ +FM(IP8_19_16) IP8_19_16 \ +FM(IP8_23_20) IP8_23_20 \ +FM(IP8_27_24) IP8_27_24 \ +FM(IP8_31_28) IP8_31_28 + +/* MOD_SEL0 */ /* 0 */ /* 1 */ +#define MOD_SEL0_11 FM(SEL_I2C3_0) FM(SEL_I2C3_1) +#define MOD_SEL0_10 FM(SEL_HSCIF0_0) FM(SEL_HSCIF0_1) +#define MOD_SEL0_9 FM(SEL_SCIF1_0) FM(SEL_SCIF1_1) +#define MOD_SEL0_8 FM(SEL_CANFD0_0) FM(SEL_CANFD0_1) +#define MOD_SEL0_7 FM(SEL_PWM4_0) FM(SEL_PWM4_1) +#define MOD_SEL0_6 FM(SEL_PWM3_0) FM(SEL_PWM3_1) +#define MOD_SEL0_5 FM(SEL_PWM2_0) FM(SEL_PWM2_1) +#define MOD_SEL0_4 FM(SEL_PWM1_0) FM(SEL_PWM1_1) +#define MOD_SEL0_3 FM(SEL_PWM0_0) FM(SEL_PWM0_1) +#define MOD_SEL0_2 FM(SEL_RFSO_0) FM(SEL_RFSO_1) +#define MOD_SEL0_1 FM(SEL_RSP_0) FM(SEL_RSP_1) +#define MOD_SEL0_0 FM(SEL_TMU_0) FM(SEL_TMU_1) + +#define PINMUX_MOD_SELS \ +\ +MOD_SEL0_11 \ +MOD_SEL0_10 \ +MOD_SEL0_9 \ +MOD_SEL0_8 \ +MOD_SEL0_7 \ +MOD_SEL0_6 \ +MOD_SEL0_5 \ +MOD_SEL0_4 \ +MOD_SEL0_3 \ +MOD_SEL0_2 \ +MOD_SEL0_1 \ +MOD_SEL0_0 + +enum { + PINMUX_RESERVED = 0, + + PINMUX_DATA_BEGIN, + GP_ALL(DATA), + PINMUX_DATA_END, + +#define F_(x, y) +#define FM(x) FN_##x, + PINMUX_FUNCTION_BEGIN, + GP_ALL(FN), + PINMUX_GPSR + PINMUX_IPSR + PINMUX_MOD_SELS + PINMUX_FUNCTION_END, +#undef F_ +#undef FM + +#define F_(x, y) +#define FM(x) x##_MARK, + PINMUX_MARK_BEGIN, + PINMUX_GPSR + PINMUX_IPSR + PINMUX_MOD_SELS + PINMUX_MARK_END, +#undef F_ +#undef FM +}; + +static const u16 pinmux_data[] = { + PINMUX_DATA_GP_ALL(), + + PINMUX_SINGLE(AVB0_RX_CTL), + PINMUX_SINGLE(AVB0_RXC), + PINMUX_SINGLE(AVB0_RD0), + PINMUX_SINGLE(AVB0_RD1), + PINMUX_SINGLE(AVB0_RD2), + PINMUX_SINGLE(AVB0_RD3), + PINMUX_SINGLE(AVB0_TX_CTL), + PINMUX_SINGLE(AVB0_TXC), + PINMUX_SINGLE(AVB0_TD0), + PINMUX_SINGLE(AVB0_TD1), + PINMUX_SINGLE(AVB0_TD2), + PINMUX_SINGLE(AVB0_TD3), + PINMUX_SINGLE(AVB0_TXCREFCLK), + PINMUX_SINGLE(AVB0_MDIO), + PINMUX_SINGLE(AVB0_MDC), + PINMUX_SINGLE(AVB0_MAGIC), + PINMUX_SINGLE(AVB0_PHY_INT), + PINMUX_SINGLE(AVB0_LINK), + PINMUX_SINGLE(AVB0_AVTP_MATCH), + + PINMUX_SINGLE(QSPI0_SPCLK), + PINMUX_SINGLE(QSPI0_MOSI_IO0), + PINMUX_SINGLE(QSPI0_MISO_IO1), + PINMUX_SINGLE(QSPI0_IO2), + PINMUX_SINGLE(QSPI0_IO3), + PINMUX_SINGLE(QSPI0_SSL), + PINMUX_SINGLE(QSPI1_SPCLK), + PINMUX_SINGLE(QSPI1_MOSI_IO0), + PINMUX_SINGLE(QSPI1_MISO_IO1), + PINMUX_SINGLE(QSPI1_IO2), + PINMUX_SINGLE(QSPI1_IO3), + PINMUX_SINGLE(QSPI1_SSL), + PINMUX_SINGLE(RPC_RESET_N), + PINMUX_SINGLE(RPC_WP_N), + PINMUX_SINGLE(RPC_INT_N), + + /* IPSR0 */ + PINMUX_IPSR_GPSR(IP0_3_0, DU_DR2), + PINMUX_IPSR_GPSR(IP0_3_0, HSCK0), + PINMUX_IPSR_GPSR(IP0_3_0, A0), + + PINMUX_IPSR_GPSR(IP0_7_4, DU_DR3), + PINMUX_IPSR_GPSR(IP0_7_4, HRTS0_N), + PINMUX_IPSR_GPSR(IP0_7_4, A1), + + PINMUX_IPSR_GPSR(IP0_11_8, DU_DR4), + PINMUX_IPSR_GPSR(IP0_11_8, HCTS0_N), + PINMUX_IPSR_GPSR(IP0_11_8, A2), + + PINMUX_IPSR_GPSR(IP0_15_12, DU_DR5), + PINMUX_IPSR_GPSR(IP0_15_12, HTX0), + PINMUX_IPSR_GPSR(IP0_15_12, A3), + + PINMUX_IPSR_GPSR(IP0_19_16, DU_DR6), + PINMUX_IPSR_GPSR(IP0_19_16, MSIOF3_RXD), + PINMUX_IPSR_GPSR(IP0_19_16, A4), + + PINMUX_IPSR_GPSR(IP0_23_20, DU_DR7), + PINMUX_IPSR_GPSR(IP0_23_20, MSIOF3_TXD), + PINMUX_IPSR_GPSR(IP0_23_20, A5), + + PINMUX_IPSR_GPSR(IP0_27_24, DU_DG2), + PINMUX_IPSR_GPSR(IP0_27_24, MSIOF3_SS1), + PINMUX_IPSR_GPSR(IP0_27_24, A6), + + PINMUX_IPSR_GPSR(IP0_31_28, DU_DG3), + PINMUX_IPSR_GPSR(IP0_31_28, MSIOF3_SS2), + PINMUX_IPSR_GPSR(IP0_31_28, A7), + PINMUX_IPSR_GPSR(IP0_31_28, PWMFSW0), + + /* IPSR1 */ + PINMUX_IPSR_GPSR(IP1_3_0, DU_DG4), + PINMUX_IPSR_GPSR(IP1_3_0, A8), + PINMUX_IPSR_MSEL(IP1_3_0, FSO_CFE_0_N_A, SEL_RFSO_0), + + PINMUX_IPSR_GPSR(IP1_7_4, DU_DG5), + PINMUX_IPSR_GPSR(IP1_7_4, A9), + PINMUX_IPSR_MSEL(IP1_7_4, FSO_CFE_1_N_A, SEL_RFSO_0), + + PINMUX_IPSR_GPSR(IP1_11_8, DU_DG6), + PINMUX_IPSR_GPSR(IP1_11_8, A10), + PINMUX_IPSR_MSEL(IP1_11_8, FSO_TOE_N_A, SEL_RFSO_0), + + PINMUX_IPSR_GPSR(IP1_15_12, DU_DG7), + PINMUX_IPSR_GPSR(IP1_15_12, A11), + PINMUX_IPSR_GPSR(IP1_15_12, IRQ1), + + PINMUX_IPSR_GPSR(IP1_19_16, DU_DB2), + PINMUX_IPSR_GPSR(IP1_19_16, A12), + PINMUX_IPSR_GPSR(IP1_19_16, IRQ2), + + PINMUX_IPSR_GPSR(IP1_23_20, DU_DB3), + PINMUX_IPSR_GPSR(IP1_23_20, A13), + PINMUX_IPSR_GPSR(IP1_23_20, FXR_CLKOUT1), + + PINMUX_IPSR_GPSR(IP1_27_24, DU_DB4), + PINMUX_IPSR_GPSR(IP1_27_24, A14), + PINMUX_IPSR_GPSR(IP1_27_24, FXR_CLKOUT2), + + PINMUX_IPSR_GPSR(IP1_31_28, DU_DB5), + PINMUX_IPSR_GPSR(IP1_31_28, A15), + PINMUX_IPSR_GPSR(IP1_31_28, FXR_TXENA_N), + + /* IPSR2 */ + PINMUX_IPSR_GPSR(IP2_3_0, DU_DB6), + PINMUX_IPSR_GPSR(IP2_3_0, A16), + PINMUX_IPSR_GPSR(IP2_3_0, FXR_TXENB_N), + + PINMUX_IPSR_GPSR(IP2_7_4, DU_DB7), + PINMUX_IPSR_GPSR(IP2_7_4, A17), + + PINMUX_IPSR_GPSR(IP2_11_8, DU_DOTCLKOUT), + PINMUX_IPSR_MSEL(IP2_11_8, SCIF_CLK_A, SEL_HSCIF0_0), + PINMUX_IPSR_GPSR(IP2_11_8, A18), + + PINMUX_IPSR_GPSR(IP2_15_12, DU_EXHSYNC_DU_HSYNC), + PINMUX_IPSR_GPSR(IP2_15_12, HRX0), + PINMUX_IPSR_GPSR(IP2_15_12, A19), + PINMUX_IPSR_GPSR(IP2_15_12, IRQ3), + + PINMUX_IPSR_GPSR(IP2_19_16, DU_EXVSYNC_DU_VSYNC), + PINMUX_IPSR_GPSR(IP2_19_16, MSIOF3_SCK), + + PINMUX_IPSR_GPSR(IP2_23_20, DU_EXODDF_DU_ODDF_DISP_CDE), + PINMUX_IPSR_GPSR(IP2_23_20, MSIOF3_SYNC), + + PINMUX_IPSR_GPSR(IP2_27_24, IRQ0), + PINMUX_IPSR_GPSR(IP2_27_24, CC5_OSCOUT), + + PINMUX_IPSR_GPSR(IP2_31_28, VI0_CLK), + PINMUX_IPSR_GPSR(IP2_31_28, MSIOF2_SCK), + PINMUX_IPSR_GPSR(IP2_31_28, SCK3), + PINMUX_IPSR_GPSR(IP2_31_28, HSCK3), + + /* IPSR3 */ + PINMUX_IPSR_GPSR(IP3_3_0, VI0_CLKENB), + PINMUX_IPSR_GPSR(IP3_3_0, MSIOF2_RXD), + PINMUX_IPSR_GPSR(IP3_3_0, RX3), + PINMUX_IPSR_GPSR(IP3_3_0, RD_WR_N), + PINMUX_IPSR_GPSR(IP3_3_0, HCTS3_N), + + PINMUX_IPSR_GPSR(IP3_7_4, VI0_HSYNC_N), + PINMUX_IPSR_GPSR(IP3_7_4, MSIOF2_TXD), + PINMUX_IPSR_GPSR(IP3_7_4, TX3), + PINMUX_IPSR_GPSR(IP3_7_4, HRTS3_N), + + PINMUX_IPSR_GPSR(IP3_11_8, VI0_VSYNC_N), + PINMUX_IPSR_GPSR(IP3_11_8, MSIOF2_SYNC), + PINMUX_IPSR_GPSR(IP3_11_8, CTS3_N), + PINMUX_IPSR_GPSR(IP3_11_8, HTX3), + + PINMUX_IPSR_GPSR(IP3_15_12, VI0_DATA0), + PINMUX_IPSR_GPSR(IP3_15_12, MSIOF2_SS1), + PINMUX_IPSR_GPSR(IP3_15_12, RTS3_N_TANS), + PINMUX_IPSR_GPSR(IP3_15_12, HRX3), + + PINMUX_IPSR_GPSR(IP3_19_16, VI0_DATA1), + PINMUX_IPSR_GPSR(IP3_19_16, MSIOF2_SS2), + PINMUX_IPSR_GPSR(IP3_19_16, SCK1), + PINMUX_IPSR_MSEL(IP3_19_16, SPEEDIN_A, SEL_RSP_0), + + PINMUX_IPSR_GPSR(IP3_23_20, VI0_DATA2), + PINMUX_IPSR_GPSR(IP3_23_20, AVB0_AVTP_PPS), + PINMUX_IPSR_MSEL(IP3_23_20, SDA3_A, SEL_I2C3_0), + + PINMUX_IPSR_GPSR(IP3_27_24, VI0_DATA3), + PINMUX_IPSR_GPSR(IP3_27_24, HSCK1), + PINMUX_IPSR_MSEL(IP3_27_24, SCL3_A, SEL_I2C3_0), + + PINMUX_IPSR_GPSR(IP3_31_28, VI0_DATA4), + PINMUX_IPSR_GPSR(IP3_31_28, HRTS1_N), + PINMUX_IPSR_MSEL(IP3_31_28, RX1_A, SEL_SCIF1_0), + + /* IPSR4 */ + PINMUX_IPSR_GPSR(IP4_3_0, VI0_DATA5), + PINMUX_IPSR_GPSR(IP4_3_0, HCTS1_N), + PINMUX_IPSR_MSEL(IP4_3_0, TX1_A, SEL_SCIF1_0), + + PINMUX_IPSR_GPSR(IP4_7_4, VI0_DATA6), + PINMUX_IPSR_GPSR(IP4_7_4, HTX1), + PINMUX_IPSR_GPSR(IP4_7_4, CTS1_N), + + PINMUX_IPSR_GPSR(IP4_11_8, VI0_DATA7), + PINMUX_IPSR_GPSR(IP4_11_8, HRX1), + PINMUX_IPSR_GPSR(IP4_11_8, RTS1_N_TANS), + + PINMUX_IPSR_GPSR(IP4_15_12, VI0_DATA8), + PINMUX_IPSR_GPSR(IP4_15_12, HSCK2), + PINMUX_IPSR_MSEL(IP4_15_12, PWM0_A, SEL_PWM0_0), + + PINMUX_IPSR_GPSR(IP4_19_16, VI0_DATA9), + PINMUX_IPSR_GPSR(IP4_19_16, HCTS2_N), + PINMUX_IPSR_MSEL(IP4_19_16, PWM1_A, SEL_PWM1_0), + PINMUX_IPSR_MSEL(IP4_19_16, FSO_CFE_0_N_B, SEL_RFSO_1), + + PINMUX_IPSR_GPSR(IP4_23_20, VI0_DATA10), + PINMUX_IPSR_GPSR(IP4_23_20, HRTS2_N), + PINMUX_IPSR_MSEL(IP4_23_20, PWM2_A, SEL_PWM2_0), + PINMUX_IPSR_MSEL(IP4_23_20, FSO_CFE_1_N_B, SEL_RFSO_1), + + PINMUX_IPSR_GPSR(IP4_27_24, VI0_DATA11), + PINMUX_IPSR_GPSR(IP4_27_24, HTX2), + PINMUX_IPSR_MSEL(IP4_27_24, PWM3_A, SEL_PWM3_0), + PINMUX_IPSR_MSEL(IP4_27_24, FSO_TOE_N_B, SEL_RFSO_1), + + PINMUX_IPSR_GPSR(IP4_31_28, VI0_FIELD), + PINMUX_IPSR_GPSR(IP4_31_28, HRX2), + PINMUX_IPSR_MSEL(IP4_31_28, PWM4_A, SEL_PWM4_0), + PINMUX_IPSR_GPSR(IP4_31_28, CS1_N), + PINMUX_IPSR_GPSR(IP4_31_28, FSCLKST2_N_A), + + /* IPSR5 */ + PINMUX_IPSR_GPSR(IP5_3_0, VI1_CLK), + PINMUX_IPSR_GPSR(IP5_3_0, MSIOF1_RXD), + PINMUX_IPSR_GPSR(IP5_3_0, CS0_N), + + PINMUX_IPSR_GPSR(IP5_7_4, VI1_CLKENB), + PINMUX_IPSR_GPSR(IP5_7_4, MSIOF1_TXD), + PINMUX_IPSR_GPSR(IP5_7_4, D0), + + PINMUX_IPSR_GPSR(IP5_11_8, VI1_HSYNC_N), + PINMUX_IPSR_GPSR(IP5_11_8, MSIOF1_SCK), + PINMUX_IPSR_GPSR(IP5_11_8, D1), + + PINMUX_IPSR_GPSR(IP5_15_12, VI1_VSYNC_N), + PINMUX_IPSR_GPSR(IP5_15_12, MSIOF1_SYNC), + PINMUX_IPSR_GPSR(IP5_15_12, D2), + + PINMUX_IPSR_GPSR(IP5_19_16, VI1_DATA0), + PINMUX_IPSR_GPSR(IP5_19_16, MSIOF1_SS1), + PINMUX_IPSR_GPSR(IP5_19_16, D3), + + PINMUX_IPSR_GPSR(IP5_23_20, VI1_DATA1), + PINMUX_IPSR_GPSR(IP5_23_20, MSIOF1_SS2), + PINMUX_IPSR_GPSR(IP5_23_20, D4), + PINMUX_IPSR_GPSR(IP5_23_20, MMC_CMD), + + PINMUX_IPSR_GPSR(IP5_27_24, VI1_DATA2), + PINMUX_IPSR_MSEL(IP5_27_24, CANFD0_TX_B, SEL_CANFD0_1), + PINMUX_IPSR_GPSR(IP5_27_24, D5), + PINMUX_IPSR_GPSR(IP5_27_24, MMC_D0), + + PINMUX_IPSR_GPSR(IP5_31_28, VI1_DATA3), + PINMUX_IPSR_MSEL(IP5_31_28, CANFD0_RX_B, SEL_CANFD0_1), + PINMUX_IPSR_GPSR(IP5_31_28, D6), + PINMUX_IPSR_GPSR(IP5_31_28, MMC_D1), + + /* IPSR6 */ + PINMUX_IPSR_GPSR(IP6_3_0, VI1_DATA4), + PINMUX_IPSR_MSEL(IP6_3_0, CANFD_CLK_B, SEL_CANFD0_1), + PINMUX_IPSR_GPSR(IP6_3_0, D7), + PINMUX_IPSR_GPSR(IP6_3_0, MMC_D2), + + PINMUX_IPSR_GPSR(IP6_7_4, VI1_DATA5), + PINMUX_IPSR_GPSR(IP6_7_4, SCK4), + PINMUX_IPSR_GPSR(IP6_7_4, D8), + PINMUX_IPSR_GPSR(IP6_7_4, MMC_D3), + + PINMUX_IPSR_GPSR(IP6_11_8, VI1_DATA6), + PINMUX_IPSR_GPSR(IP6_11_8, RX4), + PINMUX_IPSR_GPSR(IP6_11_8, D9), + PINMUX_IPSR_GPSR(IP6_11_8, MMC_CLK), + + PINMUX_IPSR_GPSR(IP6_15_12, VI1_DATA7), + PINMUX_IPSR_GPSR(IP6_15_12, TX4), + PINMUX_IPSR_GPSR(IP6_15_12, D10), + PINMUX_IPSR_GPSR(IP6_15_12, MMC_D4), + + PINMUX_IPSR_GPSR(IP6_19_16, VI1_DATA8), + PINMUX_IPSR_GPSR(IP6_19_16, CTS4_N), + PINMUX_IPSR_GPSR(IP6_19_16, D11), + PINMUX_IPSR_GPSR(IP6_19_16, MMC_D5), + + PINMUX_IPSR_GPSR(IP6_23_20, VI1_DATA9), + PINMUX_IPSR_GPSR(IP6_23_20, RTS4_N_TANS), + PINMUX_IPSR_GPSR(IP6_23_20, D12), + PINMUX_IPSR_GPSR(IP6_23_20, MMC_D6), + PINMUX_IPSR_MSEL(IP6_23_20, SCL3_B, SEL_I2C3_1), + + PINMUX_IPSR_GPSR(IP6_27_24, VI1_DATA10), + PINMUX_IPSR_GPSR(IP6_27_24, D13), + PINMUX_IPSR_GPSR(IP6_27_24, MMC_D7), + PINMUX_IPSR_MSEL(IP6_27_24, SDA3_B, SEL_I2C3_1), + + PINMUX_IPSR_GPSR(IP6_31_28, VI1_DATA11), + PINMUX_IPSR_GPSR(IP6_31_28, SCL4), + PINMUX_IPSR_GPSR(IP6_31_28, IRQ4), + PINMUX_IPSR_GPSR(IP6_31_28, D14), + PINMUX_IPSR_GPSR(IP6_31_28, MMC_WP), + + /* IPSR7 */ + PINMUX_IPSR_GPSR(IP7_3_0, VI1_FIELD), + PINMUX_IPSR_GPSR(IP7_3_0, SDA4), + PINMUX_IPSR_GPSR(IP7_3_0, IRQ5), + PINMUX_IPSR_GPSR(IP7_3_0, D15), + PINMUX_IPSR_GPSR(IP7_3_0, MMC_CD), + + PINMUX_IPSR_GPSR(IP7_7_4, SCL0), + PINMUX_IPSR_GPSR(IP7_7_4, DU_DR0), + PINMUX_IPSR_GPSR(IP7_7_4, TPU0TO0), + PINMUX_IPSR_GPSR(IP7_7_4, CLKOUT), + PINMUX_IPSR_GPSR(IP7_7_4, MSIOF0_RXD), + + PINMUX_IPSR_GPSR(IP7_11_8, SDA0), + PINMUX_IPSR_GPSR(IP7_11_8, DU_DR1), + PINMUX_IPSR_GPSR(IP7_11_8, TPU0TO1), + PINMUX_IPSR_GPSR(IP7_11_8, BS_N), + PINMUX_IPSR_GPSR(IP7_11_8, SCK0), + PINMUX_IPSR_GPSR(IP7_11_8, MSIOF0_TXD), + + PINMUX_IPSR_GPSR(IP7_15_12, SCL1), + PINMUX_IPSR_GPSR(IP7_15_12, DU_DG0), + PINMUX_IPSR_GPSR(IP7_15_12, TPU0TO2), + PINMUX_IPSR_GPSR(IP7_15_12, RD_N), + PINMUX_IPSR_GPSR(IP7_15_12, CTS0_N), + PINMUX_IPSR_GPSR(IP7_15_12, MSIOF0_SCK), + + PINMUX_IPSR_GPSR(IP7_19_16, SDA1), + PINMUX_IPSR_GPSR(IP7_19_16, DU_DG1), + PINMUX_IPSR_GPSR(IP7_19_16, TPU0TO3), + PINMUX_IPSR_GPSR(IP7_19_16, WE0_N), + PINMUX_IPSR_GPSR(IP7_19_16, RTS0_N_TANS), + PINMUX_IPSR_GPSR(IP7_19_16, MSIOF0_SYNC), + + PINMUX_IPSR_GPSR(IP7_23_20, SCL2), + PINMUX_IPSR_GPSR(IP7_23_20, DU_DB0), + PINMUX_IPSR_MSEL(IP7_23_20, TCLK1_A, SEL_TMU_0), + PINMUX_IPSR_GPSR(IP7_23_20, WE1_N), + PINMUX_IPSR_GPSR(IP7_23_20, RX0), + PINMUX_IPSR_GPSR(IP7_23_20, MSIOF0_SS1), + + PINMUX_IPSR_GPSR(IP7_27_24, SDA2), + PINMUX_IPSR_GPSR(IP7_27_24, DU_DB1), + PINMUX_IPSR_MSEL(IP7_27_24, TCLK2_A, SEL_TMU_0), + PINMUX_IPSR_GPSR(IP7_27_24, EX_WAIT0), + PINMUX_IPSR_GPSR(IP7_27_24, TX0), + PINMUX_IPSR_GPSR(IP7_27_24, MSIOF0_SS2), + + PINMUX_IPSR_GPSR(IP7_31_28, AVB0_AVTP_CAPTURE), + PINMUX_IPSR_GPSR(IP7_31_28, FSCLKST2_N_B), + + /* IPSR8 */ + PINMUX_IPSR_MSEL(IP8_3_0, CANFD0_TX_A, SEL_CANFD0_0), + PINMUX_IPSR_GPSR(IP8_3_0, FXR_TXDA), + PINMUX_IPSR_MSEL(IP8_3_0, PWM0_B, SEL_PWM0_1), + PINMUX_IPSR_GPSR(IP8_3_0, DU_DISP), + PINMUX_IPSR_GPSR(IP8_3_0, FSCLKST2_N_C), + + PINMUX_IPSR_MSEL(IP8_7_4, CANFD0_RX_A, SEL_CANFD0_0), + PINMUX_IPSR_GPSR(IP8_7_4, RXDA_EXTFXR), + PINMUX_IPSR_MSEL(IP8_7_4, PWM1_B, SEL_PWM1_1), + PINMUX_IPSR_GPSR(IP8_7_4, DU_CDE), + + PINMUX_IPSR_GPSR(IP8_11_8, CANFD1_TX), + PINMUX_IPSR_GPSR(IP8_11_8, FXR_TXDB), + PINMUX_IPSR_MSEL(IP8_11_8, PWM2_B, SEL_PWM2_1), + PINMUX_IPSR_MSEL(IP8_11_8, TCLK1_B, SEL_TMU_1), + PINMUX_IPSR_MSEL(IP8_11_8, TX1_B, SEL_SCIF1_1), + + PINMUX_IPSR_GPSR(IP8_15_12, CANFD1_RX), + PINMUX_IPSR_GPSR(IP8_15_12, RXDB_EXTFXR), + PINMUX_IPSR_MSEL(IP8_15_12, PWM3_B, SEL_PWM3_1), + PINMUX_IPSR_MSEL(IP8_15_12, TCLK2_B, SEL_TMU_1), + PINMUX_IPSR_MSEL(IP8_15_12, RX1_B, SEL_SCIF1_1), + + PINMUX_IPSR_MSEL(IP8_19_16, CANFD_CLK_A, SEL_CANFD0_0), + PINMUX_IPSR_GPSR(IP8_19_16, CLK_EXTFXR), + PINMUX_IPSR_MSEL(IP8_19_16, PWM4_B, SEL_PWM4_1), + PINMUX_IPSR_MSEL(IP8_19_16, SPEEDIN_B, SEL_RSP_1), + PINMUX_IPSR_MSEL(IP8_19_16, SCIF_CLK_B, SEL_HSCIF0_1), + + PINMUX_IPSR_GPSR(IP8_23_20, DIGRF_CLKIN), + PINMUX_IPSR_GPSR(IP8_23_20, DIGRF_CLKEN_IN), + + PINMUX_IPSR_GPSR(IP8_27_24, DIGRF_CLKOUT), + PINMUX_IPSR_GPSR(IP8_27_24, DIGRF_CLKEN_OUT), +}; + +static const struct sh_pfc_pin pinmux_pins[] = { + PINMUX_GPIO_GP_ALL(), +}; + +/* - CANFD Clock ------------------------------------------------------------ */ +static const unsigned int canfd_clk_a_pins[] = { + /* CANFD_CLK */ + RCAR_GP_PIN(1, 25), +}; +static const unsigned int canfd_clk_a_mux[] = { + CANFD_CLK_A_MARK, +}; +static const unsigned int canfd_clk_b_pins[] = { + /* CANFD_CLK */ + RCAR_GP_PIN(3, 8), +}; +static const unsigned int canfd_clk_b_mux[] = { + CANFD_CLK_B_MARK, +}; + +/* - CANFD0 ----------------------------------------------------------------- */ +static const unsigned int canfd0_data_a_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 21), RCAR_GP_PIN(1, 22), +}; +static const unsigned int canfd0_data_a_mux[] = { + CANFD0_TX_A_MARK, CANFD0_RX_A_MARK, +}; +static const unsigned int canfd0_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), +}; +static const unsigned int canfd0_data_b_mux[] = { + CANFD0_TX_B_MARK, CANFD0_RX_B_MARK, +}; + +/* - CANFD1 ----------------------------------------------------------------- */ +static const unsigned int canfd1_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), +}; +static const unsigned int canfd1_data_mux[] = { + CANFD1_TX_MARK, CANFD1_RX_MARK, +}; + +/* - DU --------------------------------------------------------------------- */ +static const unsigned int du_rgb666_pins[] = { + /* R[7:2], G[7:2], B[7:2] */ + RCAR_GP_PIN(0, 5), RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 3), + RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 1), RCAR_GP_PIN(0, 0), + RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 9), + RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 7), RCAR_GP_PIN(0, 6), + RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16), RCAR_GP_PIN(0, 15), + RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 13), RCAR_GP_PIN(0, 12), +}; +static const unsigned int du_rgb666_mux[] = { + DU_DR7_MARK, DU_DR6_MARK, DU_DR5_MARK, + DU_DR4_MARK, DU_DR3_MARK, DU_DR2_MARK, + DU_DG7_MARK, DU_DG6_MARK, DU_DG5_MARK, + DU_DG4_MARK, DU_DG3_MARK, DU_DG2_MARK, + DU_DB7_MARK, DU_DB6_MARK, DU_DB5_MARK, + DU_DB4_MARK, DU_DB3_MARK, DU_DB2_MARK, +}; +static const unsigned int du_clk_out_pins[] = { + /* DOTCLKOUT */ + RCAR_GP_PIN(0, 18), +}; +static const unsigned int du_clk_out_mux[] = { + DU_DOTCLKOUT_MARK, +}; +static const unsigned int du_sync_pins[] = { + /* EXVSYNC/VSYNC, EXHSYNC/HSYNC */ + RCAR_GP_PIN(0, 20), RCAR_GP_PIN(0, 19), +}; +static const unsigned int du_sync_mux[] = { + DU_EXVSYNC_DU_VSYNC_MARK, DU_EXHSYNC_DU_HSYNC_MARK +}; +static const unsigned int du_oddf_pins[] = { + /* EXODDF/ODDF/DISP/CDE */ + RCAR_GP_PIN(0, 21), +}; +static const unsigned int du_oddf_mux[] = { + DU_EXODDF_DU_ODDF_DISP_CDE_MARK, +}; +static const unsigned int du_cde_pins[] = { + /* CDE */ + RCAR_GP_PIN(1, 22), +}; +static const unsigned int du_cde_mux[] = { + DU_CDE_MARK, +}; +static const unsigned int du_disp_pins[] = { + /* DISP */ + RCAR_GP_PIN(1, 21), +}; +static const unsigned int du_disp_mux[] = { + DU_DISP_MARK, +}; + +/* - HSCIF0 ----------------------------------------------------------------- */ +static const unsigned int hscif0_data_pins[] = { + /* HRX, HTX */ + RCAR_GP_PIN(0, 19), RCAR_GP_PIN(0, 3), +}; +static const unsigned int hscif0_data_mux[] = { + HRX0_MARK, HTX0_MARK, +}; +static const unsigned int hscif0_clk_pins[] = { + /* HSCK */ + RCAR_GP_PIN(0, 0), +}; +static const unsigned int hscif0_clk_mux[] = { + HSCK0_MARK, +}; +static const unsigned int hscif0_ctrl_pins[] = { + /* HRTS#, HCTS# */ + RCAR_GP_PIN(0, 1), RCAR_GP_PIN(0, 2), +}; +static const unsigned int hscif0_ctrl_mux[] = { + HRTS0_N_MARK, HCTS0_N_MARK, +}; + +/* - HSCIF1 ----------------------------------------------------------------- */ +static const unsigned int hscif1_data_pins[] = { + /* HRX, HTX */ + RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 10), +}; +static const unsigned int hscif1_data_mux[] = { + HRX1_MARK, HTX1_MARK, +}; +static const unsigned int hscif1_clk_pins[] = { + /* HSCK */ + RCAR_GP_PIN(2, 7), +}; +static const unsigned int hscif1_clk_mux[] = { + HSCK1_MARK, +}; +static const unsigned int hscif1_ctrl_pins[] = { + /* HRTS#, HCTS# */ + RCAR_GP_PIN(2, 8), RCAR_GP_PIN(2, 9), +}; +static const unsigned int hscif1_ctrl_mux[] = { + HRTS1_N_MARK, HCTS1_N_MARK, +}; + +/* - HSCIF2 ----------------------------------------------------------------- */ +static const unsigned int hscif2_data_pins[] = { + /* HRX, HTX */ + RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 15), +}; +static const unsigned int hscif2_data_mux[] = { + HRX2_MARK, HTX2_MARK, +}; +static const unsigned int hscif2_clk_pins[] = { + /* HSCK */ + RCAR_GP_PIN(2, 12), +}; +static const unsigned int hscif2_clk_mux[] = { + HSCK2_MARK, +}; +static const unsigned int hscif2_ctrl_pins[] = { + /* HRTS#, HCTS# */ + RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13), +}; +static const unsigned int hscif2_ctrl_mux[] = { + HRTS2_N_MARK, HCTS2_N_MARK, +}; + +/* - HSCIF3 ----------------------------------------------------------------- */ +static const unsigned int hscif3_data_pins[] = { + /* HRX, HTX */ + RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 3), +}; +static const unsigned int hscif3_data_mux[] = { + HRX3_MARK, HTX3_MARK, +}; +static const unsigned int hscif3_clk_pins[] = { + /* HSCK */ + RCAR_GP_PIN(2, 0), +}; +static const unsigned int hscif3_clk_mux[] = { + HSCK3_MARK, +}; +static const unsigned int hscif3_ctrl_pins[] = { + /* HRTS#, HCTS# */ + RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 1), +}; +static const unsigned int hscif3_ctrl_mux[] = { + HRTS3_N_MARK, HCTS3_N_MARK, +}; + +/* - I2C0 ------------------------------------------------------------------- */ +static const unsigned int i2c0_pins[] = { + /* SDA, SCL */ + RCAR_GP_PIN(4, 1), RCAR_GP_PIN(4, 0), +}; +static const unsigned int i2c0_mux[] = { + SDA0_MARK, SCL0_MARK, +}; + +/* - I2C1 ------------------------------------------------------------------- */ +static const unsigned int i2c1_pins[] = { + /* SDA, SCL */ + RCAR_GP_PIN(4, 3), RCAR_GP_PIN(4, 2), +}; +static const unsigned int i2c1_mux[] = { + SDA1_MARK, SCL1_MARK, +}; + +/* - I2C2 ------------------------------------------------------------------- */ +static const unsigned int i2c2_pins[] = { + /* SDA, SCL */ + RCAR_GP_PIN(4, 5), RCAR_GP_PIN(4, 4), +}; +static const unsigned int i2c2_mux[] = { + SDA2_MARK, SCL2_MARK, +}; + +/* - I2C3 ------------------------------------------------------------------- */ +static const unsigned int i2c3_a_pins[] = { + /* SDA, SCL */ + RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7), +}; +static const unsigned int i2c3_a_mux[] = { + SDA3_A_MARK, SCL3_A_MARK, +}; +static const unsigned int i2c3_b_pins[] = { + /* SDA, SCL */ + RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 13), +}; +static const unsigned int i2c3_b_mux[] = { + SDA3_B_MARK, SCL3_B_MARK, +}; + +/* - I2C4 ------------------------------------------------------------------- */ +static const unsigned int i2c4_pins[] = { + /* SDA, SCL */ + RCAR_GP_PIN(3, 16), RCAR_GP_PIN(3, 15), +}; +static const unsigned int i2c4_mux[] = { + SDA4_MARK, SCL4_MARK, +}; + +/* - INTC-EX ---------------------------------------------------------------- */ +static const unsigned int intc_ex_irq0_pins[] = { + /* IRQ0 */ + RCAR_GP_PIN(1, 0), +}; +static const unsigned int intc_ex_irq0_mux[] = { + IRQ0_MARK, +}; +static const unsigned int intc_ex_irq1_pins[] = { + /* IRQ1 */ + RCAR_GP_PIN(0, 11), +}; +static const unsigned int intc_ex_irq1_mux[] = { + IRQ1_MARK, +}; +static const unsigned int intc_ex_irq2_pins[] = { + /* IRQ2 */ + RCAR_GP_PIN(0, 12), +}; +static const unsigned int intc_ex_irq2_mux[] = { + IRQ2_MARK, +}; +static const unsigned int intc_ex_irq3_pins[] = { + /* IRQ3 */ + RCAR_GP_PIN(0, 19), +}; +static const unsigned int intc_ex_irq3_mux[] = { + IRQ3_MARK, +}; +static const unsigned int intc_ex_irq4_pins[] = { + /* IRQ4 */ + RCAR_GP_PIN(3, 15), +}; +static const unsigned int intc_ex_irq4_mux[] = { + IRQ4_MARK, +}; +static const unsigned int intc_ex_irq5_pins[] = { + /* IRQ5 */ + RCAR_GP_PIN(3, 16), +}; +static const unsigned int intc_ex_irq5_mux[] = { + IRQ5_MARK, +}; + +/* - MMC -------------------------------------------------------------------- */ +static const unsigned int mmc_data1_pins[] = { + /* D0 */ + RCAR_GP_PIN(3, 6), +}; +static const unsigned int mmc_data1_mux[] = { + MMC_D0_MARK, +}; +static const unsigned int mmc_data4_pins[] = { + /* D[0:3] */ + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), + RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), +}; +static const unsigned int mmc_data4_mux[] = { + MMC_D0_MARK, MMC_D1_MARK, + MMC_D2_MARK, MMC_D3_MARK, +}; +static const unsigned int mmc_data8_pins[] = { + /* D[0:7] */ + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), + RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), + RCAR_GP_PIN(3, 11), RCAR_GP_PIN(3, 12), + RCAR_GP_PIN(3, 13), RCAR_GP_PIN(3, 14), +}; +static const unsigned int mmc_data8_mux[] = { + MMC_D0_MARK, MMC_D1_MARK, + MMC_D2_MARK, MMC_D3_MARK, + MMC_D4_MARK, MMC_D5_MARK, + MMC_D6_MARK, MMC_D7_MARK, +}; +static const unsigned int mmc_ctrl_pins[] = { + /* CLK, CMD */ + RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 5), +}; +static const unsigned int mmc_ctrl_mux[] = { + MMC_CLK_MARK, MMC_CMD_MARK, +}; +static const unsigned int mmc_cd_pins[] = { + /* CD */ + RCAR_GP_PIN(3, 16), +}; +static const unsigned int mmc_cd_mux[] = { + MMC_CD_MARK, +}; +static const unsigned int mmc_wp_pins[] = { + /* WP */ + RCAR_GP_PIN(3, 15), +}; +static const unsigned int mmc_wp_mux[] = { + MMC_WP_MARK, +}; + +/* - MSIOF0 ----------------------------------------------------------------- */ +static const unsigned int msiof0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 2), +}; +static const unsigned int msiof0_clk_mux[] = { + MSIOF0_SCK_MARK, +}; +static const unsigned int msiof0_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(4, 3), +}; +static const unsigned int msiof0_sync_mux[] = { + MSIOF0_SYNC_MARK, +}; +static const unsigned int msiof0_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(4, 4), +}; +static const unsigned int msiof0_ss1_mux[] = { + MSIOF0_SS1_MARK, +}; +static const unsigned int msiof0_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(4, 5), +}; +static const unsigned int msiof0_ss2_mux[] = { + MSIOF0_SS2_MARK, +}; +static const unsigned int msiof0_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(4, 1), +}; +static const unsigned int msiof0_txd_mux[] = { + MSIOF0_TXD_MARK, +}; +static const unsigned int msiof0_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(4, 0), +}; +static const unsigned int msiof0_rxd_mux[] = { + MSIOF0_RXD_MARK, +}; + +/* - MSIOF1 ----------------------------------------------------------------- */ +static const unsigned int msiof1_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 2), +}; +static const unsigned int msiof1_clk_mux[] = { + MSIOF1_SCK_MARK, +}; +static const unsigned int msiof1_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(3, 3), +}; +static const unsigned int msiof1_sync_mux[] = { + MSIOF1_SYNC_MARK, +}; +static const unsigned int msiof1_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(3, 4), +}; +static const unsigned int msiof1_ss1_mux[] = { + MSIOF1_SS1_MARK, +}; +static const unsigned int msiof1_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(3, 5), +}; +static const unsigned int msiof1_ss2_mux[] = { + MSIOF1_SS2_MARK, +}; +static const unsigned int msiof1_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(3, 1), +}; +static const unsigned int msiof1_txd_mux[] = { + MSIOF1_TXD_MARK, +}; +static const unsigned int msiof1_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(3, 0), +}; +static const unsigned int msiof1_rxd_mux[] = { + MSIOF1_RXD_MARK, +}; + +/* - MSIOF2 ----------------------------------------------------------------- */ +static const unsigned int msiof2_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(2, 0), +}; +static const unsigned int msiof2_clk_mux[] = { + MSIOF2_SCK_MARK, +}; +static const unsigned int msiof2_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(2, 3), +}; +static const unsigned int msiof2_sync_mux[] = { + MSIOF2_SYNC_MARK, +}; +static const unsigned int msiof2_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(2, 4), +}; +static const unsigned int msiof2_ss1_mux[] = { + MSIOF2_SS1_MARK, +}; +static const unsigned int msiof2_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(2, 5), +}; +static const unsigned int msiof2_ss2_mux[] = { + MSIOF2_SS2_MARK, +}; +static const unsigned int msiof2_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(2, 2), +}; +static const unsigned int msiof2_txd_mux[] = { + MSIOF2_TXD_MARK, +}; +static const unsigned int msiof2_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(2, 1), +}; +static const unsigned int msiof2_rxd_mux[] = { + MSIOF2_RXD_MARK, +}; + +/* - MSIOF3 ----------------------------------------------------------------- */ +static const unsigned int msiof3_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 20), +}; +static const unsigned int msiof3_clk_mux[] = { + MSIOF3_SCK_MARK, +}; +static const unsigned int msiof3_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 21), +}; +static const unsigned int msiof3_sync_mux[] = { + MSIOF3_SYNC_MARK, +}; +static const unsigned int msiof3_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 6), +}; +static const unsigned int msiof3_ss1_mux[] = { + MSIOF3_SS1_MARK, +}; +static const unsigned int msiof3_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 7), +}; +static const unsigned int msiof3_ss2_mux[] = { + MSIOF3_SS2_MARK, +}; +static const unsigned int msiof3_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 5), +}; +static const unsigned int msiof3_txd_mux[] = { + MSIOF3_TXD_MARK, +}; +static const unsigned int msiof3_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 4), +}; +static const unsigned int msiof3_rxd_mux[] = { + MSIOF3_RXD_MARK, +}; + +/* - PWM0 ------------------------------------------------------------------- */ +static const unsigned int pwm0_a_pins[] = { + RCAR_GP_PIN(2, 12), +}; +static const unsigned int pwm0_a_mux[] = { + PWM0_A_MARK, +}; +static const unsigned int pwm0_b_pins[] = { + RCAR_GP_PIN(1, 21), +}; +static const unsigned int pwm0_b_mux[] = { + PWM0_B_MARK, +}; + +/* - PWM1 ------------------------------------------------------------------- */ +static const unsigned int pwm1_a_pins[] = { + RCAR_GP_PIN(2, 13), +}; +static const unsigned int pwm1_a_mux[] = { + PWM1_A_MARK, +}; +static const unsigned int pwm1_b_pins[] = { + RCAR_GP_PIN(1, 22), +}; +static const unsigned int pwm1_b_mux[] = { + PWM1_B_MARK, +}; + +/* - PWM2 ------------------------------------------------------------------- */ +static const unsigned int pwm2_a_pins[] = { + RCAR_GP_PIN(2, 14), +}; +static const unsigned int pwm2_a_mux[] = { + PWM2_A_MARK, +}; +static const unsigned int pwm2_b_pins[] = { + RCAR_GP_PIN(1, 23), +}; +static const unsigned int pwm2_b_mux[] = { + PWM2_B_MARK, +}; + +/* - PWM3 ------------------------------------------------------------------- */ +static const unsigned int pwm3_a_pins[] = { + RCAR_GP_PIN(2, 15), +}; +static const unsigned int pwm3_a_mux[] = { + PWM3_A_MARK, +}; +static const unsigned int pwm3_b_pins[] = { + RCAR_GP_PIN(1, 24), +}; +static const unsigned int pwm3_b_mux[] = { + PWM3_B_MARK, +}; + +/* - PWM4 ------------------------------------------------------------------- */ +static const unsigned int pwm4_a_pins[] = { + RCAR_GP_PIN(2, 16), +}; +static const unsigned int pwm4_a_mux[] = { + PWM4_A_MARK, +}; +static const unsigned int pwm4_b_pins[] = { + RCAR_GP_PIN(1, 25), +}; +static const unsigned int pwm4_b_mux[] = { + PWM4_B_MARK, +}; + +/* - SCIF Clock ------------------------------------------------------------- */ +static const unsigned int scif_clk_a_pins[] = { + /* SCIF_CLK */ + RCAR_GP_PIN(0, 18), +}; +static const unsigned int scif_clk_a_mux[] = { + SCIF_CLK_A_MARK, +}; +static const unsigned int scif_clk_b_pins[] = { + /* SCIF_CLK */ + RCAR_GP_PIN(1, 25), +}; +static const unsigned int scif_clk_b_mux[] = { + SCIF_CLK_B_MARK, +}; + +/* - SCIF0 ------------------------------------------------------------------ */ +static const unsigned int scif0_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 5), +}; +static const unsigned int scif0_data_mux[] = { + RX0_MARK, TX0_MARK, +}; +static const unsigned int scif0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 1), +}; +static const unsigned int scif0_clk_mux[] = { + SCK0_MARK, +}; +static const unsigned int scif0_ctrl_pins[] = { + /* RTS#, CTS# */ + RCAR_GP_PIN(4, 3), RCAR_GP_PIN(4, 2), +}; +static const unsigned int scif0_ctrl_mux[] = { + RTS0_N_TANS_MARK, CTS0_N_MARK, +}; + +/* - SCIF1 ------------------------------------------------------------------ */ +static const unsigned int scif1_data_a_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 8), RCAR_GP_PIN(2, 9), +}; +static const unsigned int scif1_data_a_mux[] = { + RX1_A_MARK, TX1_A_MARK, +}; +static const unsigned int scif1_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(2, 5), +}; +static const unsigned int scif1_clk_mux[] = { + SCK1_MARK, +}; +static const unsigned int scif1_ctrl_pins[] = { + /* RTS#, CTS# */ + RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 10), +}; +static const unsigned int scif1_ctrl_mux[] = { + RTS1_N_TANS_MARK, CTS1_N_MARK, +}; +static const unsigned int scif1_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 23), +}; +static const unsigned int scif1_data_b_mux[] = { + RX1_B_MARK, TX1_B_MARK, +}; + +/* - SCIF3 ------------------------------------------------------------------ */ +static const unsigned int scif3_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 1), RCAR_GP_PIN(2, 2), +}; +static const unsigned int scif3_data_mux[] = { + RX3_MARK, TX3_MARK, +}; +static const unsigned int scif3_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(2, 0), +}; +static const unsigned int scif3_clk_mux[] = { + SCK3_MARK, +}; +static const unsigned int scif3_ctrl_pins[] = { + /* RTS#, CTS# */ + RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 3), +}; +static const unsigned int scif3_ctrl_mux[] = { + RTS3_N_TANS_MARK, CTS3_N_MARK, +}; + +/* - SCIF4 ------------------------------------------------------------------ */ +static const unsigned int scif4_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), +}; +static const unsigned int scif4_data_mux[] = { + RX4_MARK, TX4_MARK, +}; +static const unsigned int scif4_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 9), +}; +static const unsigned int scif4_clk_mux[] = { + SCK4_MARK, +}; +static const unsigned int scif4_ctrl_pins[] = { + /* RTS#, CTS# */ + RCAR_GP_PIN(3, 13), RCAR_GP_PIN(3, 12), +}; +static const unsigned int scif4_ctrl_mux[] = { + RTS4_N_TANS_MARK, CTS4_N_MARK, +}; + +/* - TMU -------------------------------------------------------------------- */ +static const unsigned int tmu_tclk1_a_pins[] = { + /* TCLK1 */ + RCAR_GP_PIN(4, 4), +}; +static const unsigned int tmu_tclk1_a_mux[] = { + TCLK1_A_MARK, +}; +static const unsigned int tmu_tclk1_b_pins[] = { + /* TCLK1 */ + RCAR_GP_PIN(1, 23), +}; +static const unsigned int tmu_tclk1_b_mux[] = { + TCLK1_B_MARK, +}; +static const unsigned int tmu_tclk2_a_pins[] = { + /* TCLK2 */ + RCAR_GP_PIN(4, 5), +}; +static const unsigned int tmu_tclk2_a_mux[] = { + TCLK2_A_MARK, +}; +static const unsigned int tmu_tclk2_b_pins[] = { + /* TCLK2 */ + RCAR_GP_PIN(1, 24), +}; +static const unsigned int tmu_tclk2_b_mux[] = { + TCLK2_B_MARK, +}; + +/* - VIN0 ------------------------------------------------------------------- */ +static const unsigned int vin0_data8_pins[] = { + RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5), + RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7), + RCAR_GP_PIN(2, 8), RCAR_GP_PIN(2, 9), + RCAR_GP_PIN(2, 10), RCAR_GP_PIN(2, 11), +}; +static const unsigned int vin0_data8_mux[] = { + VI0_DATA0_MARK, VI0_DATA1_MARK, + VI0_DATA2_MARK, VI0_DATA3_MARK, + VI0_DATA4_MARK, VI0_DATA5_MARK, + VI0_DATA6_MARK, VI0_DATA7_MARK, +}; +static const unsigned int vin0_data10_pins[] = { + RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5), + RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7), + RCAR_GP_PIN(2, 8), RCAR_GP_PIN(2, 9), + RCAR_GP_PIN(2, 10), RCAR_GP_PIN(2, 11), + RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 13), +}; +static const unsigned int vin0_data10_mux[] = { + VI0_DATA0_MARK, VI0_DATA1_MARK, + VI0_DATA2_MARK, VI0_DATA3_MARK, + VI0_DATA4_MARK, VI0_DATA5_MARK, + VI0_DATA6_MARK, VI0_DATA7_MARK, + VI0_DATA8_MARK, VI0_DATA9_MARK, +}; +static const unsigned int vin0_data12_pins[] = { + RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5), + RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7), + RCAR_GP_PIN(2, 8), RCAR_GP_PIN(2, 9), + RCAR_GP_PIN(2, 10), RCAR_GP_PIN(2, 11), + RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 13), + RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 15), +}; +static const unsigned int vin0_data12_mux[] = { + VI0_DATA0_MARK, VI0_DATA1_MARK, + VI0_DATA2_MARK, VI0_DATA3_MARK, + VI0_DATA4_MARK, VI0_DATA5_MARK, + VI0_DATA6_MARK, VI0_DATA7_MARK, + VI0_DATA8_MARK, VI0_DATA9_MARK, + VI0_DATA10_MARK, VI0_DATA11_MARK, +}; +static const unsigned int vin0_sync_pins[] = { + /* HSYNC#, VSYNC# */ + RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3), +}; +static const unsigned int vin0_sync_mux[] = { + VI0_HSYNC_N_MARK, VI0_VSYNC_N_MARK, +}; +static const unsigned int vin0_field_pins[] = { + /* FIELD */ + RCAR_GP_PIN(2, 16), +}; +static const unsigned int vin0_field_mux[] = { + VI0_FIELD_MARK, +}; +static const unsigned int vin0_clkenb_pins[] = { + /* CLKENB */ + RCAR_GP_PIN(2, 1), +}; +static const unsigned int vin0_clkenb_mux[] = { + VI0_CLKENB_MARK, +}; +static const unsigned int vin0_clk_pins[] = { + /* CLK */ + RCAR_GP_PIN(2, 0), +}; +static const unsigned int vin0_clk_mux[] = { + VI0_CLK_MARK, +}; + +/* - VIN1 ------------------------------------------------------------------- */ +static const unsigned int vin1_data8_pins[] = { + RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), + RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), + RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), +}; +static const unsigned int vin1_data8_mux[] = { + VI1_DATA0_MARK, VI1_DATA1_MARK, + VI1_DATA2_MARK, VI1_DATA3_MARK, + VI1_DATA4_MARK, VI1_DATA5_MARK, + VI1_DATA6_MARK, VI1_DATA7_MARK, +}; +static const unsigned int vin1_data10_pins[] = { + RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), + RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), + RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), + RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 13), +}; +static const unsigned int vin1_data10_mux[] = { + VI1_DATA0_MARK, VI1_DATA1_MARK, + VI1_DATA2_MARK, VI1_DATA3_MARK, + VI1_DATA4_MARK, VI1_DATA5_MARK, + VI1_DATA6_MARK, VI1_DATA7_MARK, + VI1_DATA8_MARK, VI1_DATA9_MARK, +}; +static const unsigned int vin1_data12_pins[] = { + RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), + RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), + RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), + RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 13), + RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), +}; +static const unsigned int vin1_data12_mux[] = { + VI1_DATA0_MARK, VI1_DATA1_MARK, + VI1_DATA2_MARK, VI1_DATA3_MARK, + VI1_DATA4_MARK, VI1_DATA5_MARK, + VI1_DATA6_MARK, VI1_DATA7_MARK, + VI1_DATA8_MARK, VI1_DATA9_MARK, + VI1_DATA10_MARK, VI1_DATA11_MARK, +}; +static const unsigned int vin1_sync_pins[] = { + /* HSYNC#, VSYNC# */ + RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), +}; +static const unsigned int vin1_sync_mux[] = { + VI1_HSYNC_N_MARK, VI1_VSYNC_N_MARK, +}; +static const unsigned int vin1_field_pins[] = { + RCAR_GP_PIN(3, 16), +}; +static const unsigned int vin1_field_mux[] = { + /* FIELD */ + VI1_FIELD_MARK, +}; +static const unsigned int vin1_clkenb_pins[] = { + RCAR_GP_PIN(3, 1), +}; +static const unsigned int vin1_clkenb_mux[] = { + /* CLKENB */ + VI1_CLKENB_MARK, +}; +static const unsigned int vin1_clk_pins[] = { + RCAR_GP_PIN(3, 0), +}; +static const unsigned int vin1_clk_mux[] = { + /* CLK */ + VI1_CLK_MARK, +}; + +static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(canfd_clk_a), + SH_PFC_PIN_GROUP(canfd_clk_b), + SH_PFC_PIN_GROUP(canfd0_data_a), + SH_PFC_PIN_GROUP(canfd0_data_b), + SH_PFC_PIN_GROUP(canfd1_data), + SH_PFC_PIN_GROUP(du_rgb666), + SH_PFC_PIN_GROUP(du_clk_out), + SH_PFC_PIN_GROUP(du_sync), + SH_PFC_PIN_GROUP(du_oddf), + SH_PFC_PIN_GROUP(du_cde), + SH_PFC_PIN_GROUP(du_disp), + SH_PFC_PIN_GROUP(hscif0_data), + SH_PFC_PIN_GROUP(hscif0_clk), + SH_PFC_PIN_GROUP(hscif0_ctrl), + SH_PFC_PIN_GROUP(hscif1_data), + SH_PFC_PIN_GROUP(hscif1_clk), + SH_PFC_PIN_GROUP(hscif1_ctrl), + SH_PFC_PIN_GROUP(hscif2_data), + SH_PFC_PIN_GROUP(hscif2_clk), + SH_PFC_PIN_GROUP(hscif2_ctrl), + SH_PFC_PIN_GROUP(hscif3_data), + SH_PFC_PIN_GROUP(hscif3_clk), + SH_PFC_PIN_GROUP(hscif3_ctrl), + SH_PFC_PIN_GROUP(i2c0), + SH_PFC_PIN_GROUP(i2c1), + SH_PFC_PIN_GROUP(i2c2), + SH_PFC_PIN_GROUP(i2c3_a), + SH_PFC_PIN_GROUP(i2c3_b), + SH_PFC_PIN_GROUP(i2c4), + SH_PFC_PIN_GROUP(intc_ex_irq0), + SH_PFC_PIN_GROUP(intc_ex_irq1), + SH_PFC_PIN_GROUP(intc_ex_irq2), + SH_PFC_PIN_GROUP(intc_ex_irq3), + SH_PFC_PIN_GROUP(intc_ex_irq4), + SH_PFC_PIN_GROUP(intc_ex_irq5), + SH_PFC_PIN_GROUP(mmc_data1), + SH_PFC_PIN_GROUP(mmc_data4), + SH_PFC_PIN_GROUP(mmc_data8), + SH_PFC_PIN_GROUP(mmc_ctrl), + SH_PFC_PIN_GROUP(mmc_cd), + SH_PFC_PIN_GROUP(mmc_wp), + SH_PFC_PIN_GROUP(msiof0_clk), + SH_PFC_PIN_GROUP(msiof0_sync), + SH_PFC_PIN_GROUP(msiof0_ss1), + SH_PFC_PIN_GROUP(msiof0_ss2), + SH_PFC_PIN_GROUP(msiof0_txd), + SH_PFC_PIN_GROUP(msiof0_rxd), + SH_PFC_PIN_GROUP(msiof1_clk), + SH_PFC_PIN_GROUP(msiof1_sync), + SH_PFC_PIN_GROUP(msiof1_ss1), + SH_PFC_PIN_GROUP(msiof1_ss2), + SH_PFC_PIN_GROUP(msiof1_txd), + SH_PFC_PIN_GROUP(msiof1_rxd), + SH_PFC_PIN_GROUP(msiof2_clk), + SH_PFC_PIN_GROUP(msiof2_sync), + SH_PFC_PIN_GROUP(msiof2_ss1), + SH_PFC_PIN_GROUP(msiof2_ss2), + SH_PFC_PIN_GROUP(msiof2_txd), + SH_PFC_PIN_GROUP(msiof2_rxd), + SH_PFC_PIN_GROUP(msiof3_clk), + SH_PFC_PIN_GROUP(msiof3_sync), + SH_PFC_PIN_GROUP(msiof3_ss1), + SH_PFC_PIN_GROUP(msiof3_ss2), + SH_PFC_PIN_GROUP(msiof3_txd), + SH_PFC_PIN_GROUP(msiof3_rxd), + SH_PFC_PIN_GROUP(pwm0_a), + SH_PFC_PIN_GROUP(pwm0_b), + SH_PFC_PIN_GROUP(pwm1_a), + SH_PFC_PIN_GROUP(pwm1_b), + SH_PFC_PIN_GROUP(pwm2_a), + SH_PFC_PIN_GROUP(pwm2_b), + SH_PFC_PIN_GROUP(pwm3_a), + SH_PFC_PIN_GROUP(pwm3_b), + SH_PFC_PIN_GROUP(pwm4_a), + SH_PFC_PIN_GROUP(pwm4_b), + SH_PFC_PIN_GROUP(scif_clk_a), + SH_PFC_PIN_GROUP(scif_clk_b), + SH_PFC_PIN_GROUP(scif0_data), + SH_PFC_PIN_GROUP(scif0_clk), + SH_PFC_PIN_GROUP(scif0_ctrl), + SH_PFC_PIN_GROUP(scif1_data_a), + SH_PFC_PIN_GROUP(scif1_clk), + SH_PFC_PIN_GROUP(scif1_ctrl), + SH_PFC_PIN_GROUP(scif1_data_b), + SH_PFC_PIN_GROUP(scif3_data), + SH_PFC_PIN_GROUP(scif3_clk), + SH_PFC_PIN_GROUP(scif3_ctrl), + SH_PFC_PIN_GROUP(scif4_data), + SH_PFC_PIN_GROUP(scif4_clk), + SH_PFC_PIN_GROUP(scif4_ctrl), + SH_PFC_PIN_GROUP(tmu_tclk1_a), + SH_PFC_PIN_GROUP(tmu_tclk1_b), + SH_PFC_PIN_GROUP(tmu_tclk2_a), + SH_PFC_PIN_GROUP(tmu_tclk2_b), + SH_PFC_PIN_GROUP(vin0_data8), + SH_PFC_PIN_GROUP(vin0_data10), + SH_PFC_PIN_GROUP(vin0_data12), + SH_PFC_PIN_GROUP(vin0_sync), + SH_PFC_PIN_GROUP(vin0_field), + SH_PFC_PIN_GROUP(vin0_clkenb), + SH_PFC_PIN_GROUP(vin0_clk), + SH_PFC_PIN_GROUP(vin1_data8), + SH_PFC_PIN_GROUP(vin1_data10), + SH_PFC_PIN_GROUP(vin1_data12), + SH_PFC_PIN_GROUP(vin1_sync), + SH_PFC_PIN_GROUP(vin1_field), + SH_PFC_PIN_GROUP(vin1_clkenb), + SH_PFC_PIN_GROUP(vin1_clk), +}; + +static const char * const canfd_clk_groups[] = { + "canfd_clk_a", + "canfd_clk_b", +}; + +static const char * const canfd0_groups[] = { + "canfd0_data_a", + "canfd0_data_b", +}; + +static const char * const canfd1_groups[] = { + "canfd1_data", +}; + +static const char * const du_groups[] = { + "du_rgb666", + "du_clk_out", + "du_sync", + "du_oddf", + "du_cde", + "du_disp", +}; + +static const char * const hscif0_groups[] = { + "hscif0_data", + "hscif0_clk", + "hscif0_ctrl", +}; + +static const char * const hscif1_groups[] = { + "hscif1_data", + "hscif1_clk", + "hscif1_ctrl", +}; + +static const char * const hscif2_groups[] = { + "hscif2_data", + "hscif2_clk", + "hscif2_ctrl", +}; + +static const char * const hscif3_groups[] = { + "hscif3_data", + "hscif3_clk", + "hscif3_ctrl", +}; + +static const char * const i2c0_groups[] = { + "i2c0", +}; + +static const char * const i2c1_groups[] = { + "i2c1", +}; + +static const char * const i2c2_groups[] = { + "i2c2", +}; + +static const char * const i2c3_groups[] = { + "i2c3_a", + "i2c3_b", +}; + +static const char * const i2c4_groups[] = { + "i2c4", +}; + +static const char * const intc_ex_groups[] = { + "intc_ex_irq0", + "intc_ex_irq1", + "intc_ex_irq2", + "intc_ex_irq3", + "intc_ex_irq4", + "intc_ex_irq5", +}; + +static const char * const mmc_groups[] = { + "mmc_data1", + "mmc_data4", + "mmc_data8", + "mmc_ctrl", + "mmc_cd", + "mmc_wp", +}; + +static const char * const msiof0_groups[] = { + "msiof0_clk", + "msiof0_sync", + "msiof0_ss1", + "msiof0_ss2", + "msiof0_txd", + "msiof0_rxd", +}; + +static const char * const msiof1_groups[] = { + "msiof1_clk", + "msiof1_sync", + "msiof1_ss1", + "msiof1_ss2", + "msiof1_txd", + "msiof1_rxd", +}; + +static const char * const msiof2_groups[] = { + "msiof2_clk", + "msiof2_sync", + "msiof2_ss1", + "msiof2_ss2", + "msiof2_txd", + "msiof2_rxd", +}; + +static const char * const msiof3_groups[] = { + "msiof3_clk", + "msiof3_sync", + "msiof3_ss1", + "msiof3_ss2", + "msiof3_txd", + "msiof3_rxd", +}; + +static const char * const pwm0_groups[] = { + "pwm0_a", + "pwm0_b", +}; + +static const char * const pwm1_groups[] = { + "pwm1_a", + "pwm1_b", +}; + +static const char * const pwm2_groups[] = { + "pwm2_a", + "pwm2_b", +}; + +static const char * const pwm3_groups[] = { + "pwm3_a", + "pwm3_b", +}; + +static const char * const pwm4_groups[] = { + "pwm4_a", + "pwm4_b", +}; + +static const char * const scif_clk_groups[] = { + "scif_clk_a", + "scif_clk_b", +}; + +static const char * const scif0_groups[] = { + "scif0_data", + "scif0_clk", + "scif0_ctrl", +}; + +static const char * const scif1_groups[] = { + "scif1_data_a", + "scif1_clk", + "scif1_ctrl", + "scif1_data_b", +}; + +static const char * const scif3_groups[] = { + "scif3_data", + "scif3_clk", + "scif3_ctrl", +}; + +static const char * const scif4_groups[] = { + "scif4_data", + "scif4_clk", + "scif4_ctrl", +}; + +static const char * const tmu_groups[] = { + "tmu_tclk1_a", + "tmu_tclk1_b", + "tmu_tclk2_a", + "tmu_tclk2_b", +}; + +static const char * const vin0_groups[] = { + "vin0_data8", + "vin0_data10", + "vin0_data12", + "vin0_sync", + "vin0_field", + "vin0_clkenb", + "vin0_clk", +}; + +static const char * const vin1_groups[] = { + "vin1_data8", + "vin1_data10", + "vin1_data12", + "vin1_sync", + "vin1_field", + "vin1_clkenb", + "vin1_clk", +}; + +static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(canfd_clk), + SH_PFC_FUNCTION(canfd0), + SH_PFC_FUNCTION(canfd1), + SH_PFC_FUNCTION(du), + SH_PFC_FUNCTION(hscif0), + SH_PFC_FUNCTION(hscif1), + SH_PFC_FUNCTION(hscif2), + SH_PFC_FUNCTION(hscif3), + SH_PFC_FUNCTION(i2c0), + SH_PFC_FUNCTION(i2c1), + SH_PFC_FUNCTION(i2c2), + SH_PFC_FUNCTION(i2c3), + SH_PFC_FUNCTION(i2c4), + SH_PFC_FUNCTION(intc_ex), + SH_PFC_FUNCTION(mmc), + SH_PFC_FUNCTION(msiof0), + SH_PFC_FUNCTION(msiof1), + SH_PFC_FUNCTION(msiof2), + SH_PFC_FUNCTION(msiof3), + SH_PFC_FUNCTION(pwm0), + SH_PFC_FUNCTION(pwm1), + SH_PFC_FUNCTION(pwm2), + SH_PFC_FUNCTION(pwm3), + SH_PFC_FUNCTION(pwm4), + SH_PFC_FUNCTION(scif_clk), + SH_PFC_FUNCTION(scif0), + SH_PFC_FUNCTION(scif1), + SH_PFC_FUNCTION(scif3), + SH_PFC_FUNCTION(scif4), + SH_PFC_FUNCTION(tmu), + SH_PFC_FUNCTION(vin0), + SH_PFC_FUNCTION(vin1), +}; + +static const struct pinmux_cfg_reg pinmux_config_regs[] = { +#define F_(x, y) FN_##y +#define FM(x) FN_##x + { PINMUX_CFG_REG("GPSR0", 0xe6060100, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_0_21_FN, GPSR0_21, + GP_0_20_FN, GPSR0_20, + GP_0_19_FN, GPSR0_19, + GP_0_18_FN, GPSR0_18, + GP_0_17_FN, GPSR0_17, + GP_0_16_FN, GPSR0_16, + GP_0_15_FN, GPSR0_15, + GP_0_14_FN, GPSR0_14, + GP_0_13_FN, GPSR0_13, + GP_0_12_FN, GPSR0_12, + GP_0_11_FN, GPSR0_11, + GP_0_10_FN, GPSR0_10, + GP_0_9_FN, GPSR0_9, + GP_0_8_FN, GPSR0_8, + GP_0_7_FN, GPSR0_7, + GP_0_6_FN, GPSR0_6, + GP_0_5_FN, GPSR0_5, + GP_0_4_FN, GPSR0_4, + GP_0_3_FN, GPSR0_3, + GP_0_2_FN, GPSR0_2, + GP_0_1_FN, GPSR0_1, + GP_0_0_FN, GPSR0_0, } + }, + { PINMUX_CFG_REG("GPSR1", 0xe6060104, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_1_27_FN, GPSR1_27, + GP_1_26_FN, GPSR1_26, + GP_1_25_FN, GPSR1_25, + GP_1_24_FN, GPSR1_24, + GP_1_23_FN, GPSR1_23, + GP_1_22_FN, GPSR1_22, + GP_1_21_FN, GPSR1_21, + GP_1_20_FN, GPSR1_20, + GP_1_19_FN, GPSR1_19, + GP_1_18_FN, GPSR1_18, + GP_1_17_FN, GPSR1_17, + GP_1_16_FN, GPSR1_16, + GP_1_15_FN, GPSR1_15, + GP_1_14_FN, GPSR1_14, + GP_1_13_FN, GPSR1_13, + GP_1_12_FN, GPSR1_12, + GP_1_11_FN, GPSR1_11, + GP_1_10_FN, GPSR1_10, + GP_1_9_FN, GPSR1_9, + GP_1_8_FN, GPSR1_8, + GP_1_7_FN, GPSR1_7, + GP_1_6_FN, GPSR1_6, + GP_1_5_FN, GPSR1_5, + GP_1_4_FN, GPSR1_4, + GP_1_3_FN, GPSR1_3, + GP_1_2_FN, GPSR1_2, + GP_1_1_FN, GPSR1_1, + GP_1_0_FN, GPSR1_0, } + }, + { PINMUX_CFG_REG("GPSR2", 0xe6060108, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_2_16_FN, GPSR2_16, + GP_2_15_FN, GPSR2_15, + GP_2_14_FN, GPSR2_14, + GP_2_13_FN, GPSR2_13, + GP_2_12_FN, GPSR2_12, + GP_2_11_FN, GPSR2_11, + GP_2_10_FN, GPSR2_10, + GP_2_9_FN, GPSR2_9, + GP_2_8_FN, GPSR2_8, + GP_2_7_FN, GPSR2_7, + GP_2_6_FN, GPSR2_6, + GP_2_5_FN, GPSR2_5, + GP_2_4_FN, GPSR2_4, + GP_2_3_FN, GPSR2_3, + GP_2_2_FN, GPSR2_2, + GP_2_1_FN, GPSR2_1, + GP_2_0_FN, GPSR2_0, } + }, + { PINMUX_CFG_REG("GPSR3", 0xe606010c, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_3_16_FN, GPSR3_16, + GP_3_15_FN, GPSR3_15, + GP_3_14_FN, GPSR3_14, + GP_3_13_FN, GPSR3_13, + GP_3_12_FN, GPSR3_12, + GP_3_11_FN, GPSR3_11, + GP_3_10_FN, GPSR3_10, + GP_3_9_FN, GPSR3_9, + GP_3_8_FN, GPSR3_8, + GP_3_7_FN, GPSR3_7, + GP_3_6_FN, GPSR3_6, + GP_3_5_FN, GPSR3_5, + GP_3_4_FN, GPSR3_4, + GP_3_3_FN, GPSR3_3, + GP_3_2_FN, GPSR3_2, + GP_3_1_FN, GPSR3_1, + GP_3_0_FN, GPSR3_0, } + }, + { PINMUX_CFG_REG("GPSR4", 0xe6060110, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_4_5_FN, GPSR4_5, + GP_4_4_FN, GPSR4_4, + GP_4_3_FN, GPSR4_3, + GP_4_2_FN, GPSR4_2, + GP_4_1_FN, GPSR4_1, + GP_4_0_FN, GPSR4_0, } + }, + { PINMUX_CFG_REG("GPSR5", 0xe6060114, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_5_14_FN, GPSR5_14, + GP_5_13_FN, GPSR5_13, + GP_5_12_FN, GPSR5_12, + GP_5_11_FN, GPSR5_11, + GP_5_10_FN, GPSR5_10, + GP_5_9_FN, GPSR5_9, + GP_5_8_FN, GPSR5_8, + GP_5_7_FN, GPSR5_7, + GP_5_6_FN, GPSR5_6, + GP_5_5_FN, GPSR5_5, + GP_5_4_FN, GPSR5_4, + GP_5_3_FN, GPSR5_3, + GP_5_2_FN, GPSR5_2, + GP_5_1_FN, GPSR5_1, + GP_5_0_FN, GPSR5_0, } + }, +#undef F_ +#undef FM + +#define F_(x, y) x, +#define FM(x) FN_##x, + { PINMUX_CFG_REG("IPSR0", 0xe6060200, 32, 4) { + IP0_31_28 + IP0_27_24 + IP0_23_20 + IP0_19_16 + IP0_15_12 + IP0_11_8 + IP0_7_4 + IP0_3_0 } + }, + { PINMUX_CFG_REG("IPSR1", 0xe6060204, 32, 4) { + IP1_31_28 + IP1_27_24 + IP1_23_20 + IP1_19_16 + IP1_15_12 + IP1_11_8 + IP1_7_4 + IP1_3_0 } + }, + { PINMUX_CFG_REG("IPSR2", 0xe6060208, 32, 4) { + IP2_31_28 + IP2_27_24 + IP2_23_20 + IP2_19_16 + IP2_15_12 + IP2_11_8 + IP2_7_4 + IP2_3_0 } + }, + { PINMUX_CFG_REG("IPSR3", 0xe606020c, 32, 4) { + IP3_31_28 + IP3_27_24 + IP3_23_20 + IP3_19_16 + IP3_15_12 + IP3_11_8 + IP3_7_4 + IP3_3_0 } + }, + { PINMUX_CFG_REG("IPSR4", 0xe6060210, 32, 4) { + IP4_31_28 + IP4_27_24 + IP4_23_20 + IP4_19_16 + IP4_15_12 + IP4_11_8 + IP4_7_4 + IP4_3_0 } + }, + { PINMUX_CFG_REG("IPSR5", 0xe6060214, 32, 4) { + IP5_31_28 + IP5_27_24 + IP5_23_20 + IP5_19_16 + IP5_15_12 + IP5_11_8 + IP5_7_4 + IP5_3_0 } + }, + { PINMUX_CFG_REG("IPSR6", 0xe6060218, 32, 4) { + IP6_31_28 + IP6_27_24 + IP6_23_20 + IP6_19_16 + IP6_15_12 + IP6_11_8 + IP6_7_4 + IP6_3_0 } + }, + { PINMUX_CFG_REG("IPSR7", 0xe606021c, 32, 4) { + IP7_31_28 + IP7_27_24 + IP7_23_20 + IP7_19_16 + IP7_15_12 + IP7_11_8 + IP7_7_4 + IP7_3_0 } + }, + { PINMUX_CFG_REG("IPSR8", 0xe6060220, 32, 4) { + IP8_31_28 + IP8_27_24 + IP8_23_20 + IP8_19_16 + IP8_15_12 + IP8_11_8 + IP8_7_4 + IP8_3_0 } + }, +#undef F_ +#undef FM + +#define F_(x, y) x, +#define FM(x) FN_##x, + { PINMUX_CFG_REG_VAR("MOD_SEL0", 0xe6060500, 32, + 4, 4, 4, 4, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) { + /* RESERVED 31, 30, 29, 28 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* RESERVED 27, 26, 25, 24 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* RESERVED 23, 22, 21, 20 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* RESERVED 19, 18, 17, 16 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* RESERVED 15, 14, 13, 12 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + MOD_SEL0_11 + MOD_SEL0_10 + MOD_SEL0_9 + MOD_SEL0_8 + MOD_SEL0_7 + MOD_SEL0_6 + MOD_SEL0_5 + MOD_SEL0_4 + MOD_SEL0_3 + MOD_SEL0_2 + MOD_SEL0_1 + MOD_SEL0_0 } + }, + { }, +}; + +static int r8a77970_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, + u32 *pocctrl) +{ + int bit = pin & 0x1f; + + *pocctrl = 0xe6060380; + if (pin >= RCAR_GP_PIN(0, 0) && pin <= RCAR_GP_PIN(0, 21)) + return bit; + if (pin >= RCAR_GP_PIN(2, 0) && pin <= RCAR_GP_PIN(2, 9)) + return bit + 22; + + *pocctrl += 4; + if (pin >= RCAR_GP_PIN(2, 10) && pin <= RCAR_GP_PIN(2, 16)) + return bit - 10; + if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 16)) + return bit + 7; + + return -EINVAL; +} + +static const struct sh_pfc_soc_operations pinmux_ops = { + .pin_to_pocctrl = r8a77970_pin_to_pocctrl, +}; + +const struct sh_pfc_soc_info r8a77970_pinmux_info = { + .name = "r8a77970_pfc", + .ops = &pinmux_ops, + .unlock_reg = 0xe6060000, /* PMMR */ + + .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, + + .pins = pinmux_pins, + .nr_pins = ARRAY_SIZE(pinmux_pins), + .groups = pinmux_groups, + .nr_groups = ARRAY_SIZE(pinmux_groups), + .functions = pinmux_functions, + .nr_functions = ARRAY_SIZE(pinmux_functions), + + .cfg_regs = pinmux_config_regs, + + .pinmux_data = pinmux_data, + .pinmux_data_size = ARRAY_SIZE(pinmux_data), +}; diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h index efe07bcca8d0..5747ab0472df 100644 --- a/drivers/pinctrl/sh-pfc/sh_pfc.h +++ b/drivers/pinctrl/sh-pfc/sh_pfc.h @@ -283,6 +283,7 @@ extern const struct sh_pfc_soc_info r8a7794_pinmux_info; extern const struct sh_pfc_soc_info r8a7795_pinmux_info; extern const struct sh_pfc_soc_info r8a7795es1_pinmux_info; extern const struct sh_pfc_soc_info r8a7796_pinmux_info; +extern const struct sh_pfc_soc_info r8a77970_pinmux_info; extern const struct sh_pfc_soc_info r8a77995_pinmux_info; extern const struct sh_pfc_soc_info sh7203_pinmux_info; extern const struct sh_pfc_soc_info sh7264_pinmux_info; -- cgit From 7c4a3906475cba91c51e10a79e681b4f9ec6ec14 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 14 Nov 2017 15:41:16 +0000 Subject: pinctrl: sh-pfc: r8a7794: Add can_clk function This patch adds can_clk function to r8a7745/r8a7794 which is cleaner, and allows for independent configuration. We keep the can_clk* pins definitions from within can0_groups and can1_groups for uniformity and backwards compatibility. Signed-off-by: Fabrizio Castro Reviewed-by: Ramesh Shanmugasundaram Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7794.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index e5b3d5fa4aa0..c557bc8da10d 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -3858,6 +3858,10 @@ static const char * const can0_groups[] = { "can0_data_b", "can0_data_c", "can0_data_d", + /* + * Retained for backwards compatibility, use can_clk_groups in new + * designs. + */ "can_clk", "can_clk_b", "can_clk_c", @@ -3869,6 +3873,21 @@ static const char * const can1_groups[] = { "can1_data_b", "can1_data_c", "can1_data_d", + /* + * Retained for backwards compatibility, use can_clk_groups in new + * designs. + */ + "can_clk", + "can_clk_b", + "can_clk_c", + "can_clk_d", +}; + +/* + * can_clk_groups allows for independent configuration, use can_clk function + * in new designs. + */ +static const char * const can_clk_groups[] = { "can_clk", "can_clk_b", "can_clk_c", @@ -4248,6 +4267,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(avb), SH_PFC_FUNCTION(can0), SH_PFC_FUNCTION(can1), + SH_PFC_FUNCTION(can_clk), SH_PFC_FUNCTION(du0), SH_PFC_FUNCTION(du1), SH_PFC_FUNCTION(eth), -- cgit From 57eec02caee60332b8052615e7257f932ae07abc Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 14 Nov 2017 15:41:17 +0000 Subject: pinctrl: sh-pfc: r8a7791: Add can_clk function This patch adds can_clk function to r8a7743/r8a7791 which is cleaner, and allows for independent configuration. We keep the can_clk* pins definitions from within can0_groups and can1_groups for uniformity and backwards compatibility. Signed-off-by: Fabrizio Castro Reviewed-by: Ramesh Shanmugasundaram Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 10bd35f8c894..c01ef02d326b 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -4826,6 +4826,10 @@ static const char * const can0_groups[] = { "can0_data_d", "can0_data_e", "can0_data_f", + /* + * Retained for backwards compatibility, use can_clk_groups in new + * designs. + */ "can_clk", "can_clk_b", "can_clk_c", @@ -4837,6 +4841,21 @@ static const char * const can1_groups[] = { "can1_data_b", "can1_data_c", "can1_data_d", + /* + * Retained for backwards compatibility, use can_clk_groups in new + * designs. + */ + "can_clk", + "can_clk_b", + "can_clk_c", + "can_clk_d", +}; + +/* + * can_clk_groups allows for independent configuration, use can_clk function + * in new designs. + */ +static const char * const can_clk_groups[] = { "can_clk", "can_clk_b", "can_clk_c", @@ -5308,7 +5327,7 @@ static const char * const vin2_groups[] = { }; static const struct { - struct sh_pfc_function common[56]; + struct sh_pfc_function common[57]; struct sh_pfc_function r8a779x[2]; } pinmux_functions = { .common = { @@ -5316,6 +5335,7 @@ static const struct { SH_PFC_FUNCTION(avb), SH_PFC_FUNCTION(can0), SH_PFC_FUNCTION(can1), + SH_PFC_FUNCTION(can_clk), SH_PFC_FUNCTION(du), SH_PFC_FUNCTION(du0), SH_PFC_FUNCTION(du1), -- cgit From af4b609e6f7010094a8f14ff620588fad87e8553 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Wed, 15 Nov 2017 16:25:21 +0100 Subject: pinctrl: sh-pfc: r8a77995: Add missing pins SCL0 and SDA0 to pinmux data Required for I2C0 operation. Signed-off-by: Ulrich Hecht Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a77995.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c index 89b7541ab1ed..2c9a71a59fc3 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c @@ -518,6 +518,8 @@ static const u16 pinmux_data[] = { PINMUX_SINGLE(QSPI0_MISO_IO1), PINMUX_SINGLE(QSPI0_MOSI_IO0), PINMUX_SINGLE(QSPI0_SPCLK), + PINMUX_SINGLE(SCL0), + PINMUX_SINGLE(SDA0), /* IPSR0 */ PINMUX_IPSR_MSEL(IP0_3_0, IRQ0_A, SEL_IRQ_0_0), -- cgit From 82d2de5a4f646f7265ac5bc779f4a58164f2c0e9 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Thu, 16 Nov 2017 12:14:51 +0900 Subject: pinctrl: sh-pfc: r8a7795: Add GP-1-28 port pin support This patch supports GP-1-28 port pin of R8A7795 ES2.0 SoC added in Rev.0.54E of the R-Car Gen3 Hardware User's Manual or later version. Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Kaneko [geert: Update forgotten PUEN2 entry] Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index 34a2dc471e5a..a1358a1e67b7 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -20,7 +20,7 @@ #define CPU_ALL_PORT(fn, sfx) \ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_28(1, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS), \ @@ -55,6 +55,7 @@ #define GPSR0_0 F_(D0, IP5_15_12) /* GPSR1 */ +#define GPSR1_28 FM(CLKOUT) #define GPSR1_27 F_(EX_WAIT0_A, IP5_11_8) #define GPSR1_26 F_(WE1_N, IP5_7_4) #define GPSR1_25 F_(WE0_N, IP5_3_0) @@ -368,7 +369,7 @@ GPSR6_31 \ GPSR6_30 \ GPSR6_29 \ - GPSR6_28 \ + GPSR1_28 GPSR6_28 \ GPSR1_27 GPSR6_27 \ GPSR1_26 GPSR6_26 \ GPSR1_25 GPSR5_25 GPSR6_25 \ @@ -548,7 +549,7 @@ MOD_SEL0_4_3 MOD_SEL1_4 \ FM(AVB_TX_CTL) FM(AVB_TXC) FM(AVB_TD0) FM(AVB_TD1) FM(AVB_TD2) FM(AVB_TD3) \ FM(AVB_RX_CTL) FM(AVB_RXC) FM(AVB_RD0) FM(AVB_RD1) FM(AVB_RD2) FM(AVB_RD3) \ FM(AVB_TXCREFCLK) FM(AVB_MDIO) \ - FM(CLKOUT) FM(PRESETOUT) \ + FM(PRESETOUT) \ FM(DU_DOTCLKIN0) FM(DU_DOTCLKIN1) FM(DU_DOTCLKIN2) FM(DU_DOTCLKIN3) \ FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) FM(TDI) FM(TCK) FM(TRST) FM(EXTALR) @@ -587,6 +588,7 @@ static const u16 pinmux_data[] = { PINMUX_SINGLE(AVS1), PINMUX_SINGLE(AVS2), + PINMUX_SINGLE(CLKOUT), PINMUX_SINGLE(HDMI0_CEC), PINMUX_SINGLE(HDMI1_CEC), PINMUX_SINGLE(I2C_SEL_0_1), @@ -4733,7 +4735,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { 0, 0, 0, 0, 0, 0, - 0, 0, + GP_1_28_FN, GPSR1_28, GP_1_27_FN, GPSR1_27, GP_1_26_FN, GPSR1_26, GP_1_25_FN, GPSR1_25, @@ -5335,7 +5337,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(1, 19), 0, 3 }, /* A19 */ } }, { PINMUX_DRIVE_REG("DRVCTRL8", 0xe6060320) { - { PIN_NUMBER('F', 1), 28, 3 }, /* CLKOUT */ + { RCAR_GP_PIN(1, 28), 28, 3 }, /* CLKOUT */ { RCAR_GP_PIN(1, 20), 24, 3 }, /* CS0 */ { RCAR_GP_PIN(1, 21), 20, 3 }, /* CS1_A26 */ { RCAR_GP_PIN(1, 22), 16, 3 }, /* BS */ @@ -5596,7 +5598,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [31] = RCAR_GP_PIN(1, 19), /* A19 */ } }, { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) { - [ 0] = PIN_NUMBER('F', 1), /* CLKOUT */ + [ 0] = RCAR_GP_PIN(1, 28), /* CLKOUT */ [ 1] = RCAR_GP_PIN(1, 20), /* CS0_N */ [ 2] = RCAR_GP_PIN(1, 21), /* CS1_N */ [ 3] = RCAR_GP_PIN(1, 22), /* BS_N */ -- cgit From b16cd900de7911f96af17327a081a2141a0b763f Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Thu, 16 Nov 2017 12:16:00 +0900 Subject: pinctrl: sh-pfc: r8a7795-es1: Fix MOD_SEL1 bit[25:24] to 0x3 when using STP_ISEN_1_D This patch fixes the implementation incorrect of MOD_SEL1 bit[25:24] value when STP_ISEN_1_D pin function is selected for IPSR16 bit[27:24]. This is a correction to the incorrect implementation of MOD_SEL register pin assignment for R8A7795 SoC specification of R-Car Gen3 Hardware User's Manual Rev.0.51E. Fixes: 0b0ffc96dbe30fa9 ("pinctrl: sh-pfc: Initial R8A7795 PFC support) Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Kaneko Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c index 1d4d84f34d60..292e35d4d2f4 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c @@ -1397,7 +1397,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP16_27_24, AUDIO_CLKOUT_B, SEL_ADG_1), PINMUX_IPSR_MSEL(IP16_27_24, SSI_SCK2_B, SEL_SSI_1), PINMUX_IPSR_MSEL(IP16_27_24, TS_SDEN1_D, SEL_TSIF1_3), - PINMUX_IPSR_MSEL(IP16_27_24, STP_ISEN_1_D, SEL_SSP1_1_2), + PINMUX_IPSR_MSEL(IP16_27_24, STP_ISEN_1_D, SEL_SSP1_1_3), PINMUX_IPSR_MSEL(IP16_27_24, STP_OPWM_0_E, SEL_SSP1_0_4), PINMUX_IPSR_MSEL(IP16_27_24, RIF3_D0_B, SEL_DRIF3_1), PINMUX_IPSR_MSEL(IP16_27_24, TCLK2_B, SEL_TIMER_TMU_1), -- cgit From 7716c51b5e96a289df954b1fe91faf711fb51da9 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Thu, 16 Nov 2017 12:16:48 +0900 Subject: pinctrl: sh-pfc: r8a7795: Fix to delete A20..A25 pins function definitions This patch fixes the macro definitions of A20..A25 pins function deleted. This is a correction because IPSR register specification for R8A7795 ES2.0 SoC was changed in R-Car Gen3 Hardware User's Manual Rev.0.53E. Fixes: b205914c8f822ef2 ("pinctrl: sh-pfc: r8a7795: Add support for R-Car H3 ES2.0") Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Kaneko Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index a1358a1e67b7..a97256cd25df 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -219,12 +219,12 @@ #define IP0_27_24 FM(IRQ0) FM(QPOLB) F_(0, 0) FM(DU_CDE) FM(VI4_DATA0_B) FM(CAN0_TX_B) FM(CANFD0_TX_B) FM(MSIOF3_SS2_E) 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_31_28 FM(IRQ1) FM(QPOLA) F_(0, 0) FM(DU_DISP) FM(VI4_DATA1_B) FM(CAN0_RX_B) FM(CANFD0_RX_B) FM(MSIOF3_SS1_E) 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 IP1_3_0 FM(IRQ2) FM(QCPV_QDE) F_(0, 0) FM(DU_EXODDF_DU_ODDF_DISP_CDE) FM(VI4_DATA2_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SYNC_E) F_(0, 0) FM(PWM3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_7_4 FM(IRQ3) FM(QSTVB_QVE) FM(A25) FM(DU_DOTCLKOUT1) FM(VI4_DATA3_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SCK_E) F_(0, 0) FM(PWM4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_11_8 FM(IRQ4) FM(QSTH_QHS) FM(A24) FM(DU_EXHSYNC_DU_HSYNC) FM(VI4_DATA4_B) F_(0, 0) F_(0, 0) FM(MSIOF3_RXD_E) F_(0, 0) FM(PWM5_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_15_12 FM(IRQ5) FM(QSTB_QHE) FM(A23) FM(DU_EXVSYNC_DU_VSYNC) FM(VI4_DATA5_B) FM(FSCLKST2_N_B) F_(0, 0) FM(MSIOF3_TXD_E) F_(0, 0) FM(PWM6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_19_16 FM(PWM0) FM(AVB_AVTP_PPS)FM(A22) F_(0, 0) FM(VI4_DATA6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IECLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_23_20 FM(PWM1_A) F_(0, 0) FM(A21) FM(HRX3_D) FM(VI4_DATA7_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IERX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_27_24 FM(PWM2_A) F_(0, 0) FM(A20) FM(HTX3_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IETX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_7_4 FM(IRQ3) FM(QSTVB_QVE) F_(0, 0) FM(DU_DOTCLKOUT1) FM(VI4_DATA3_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SCK_E) F_(0, 0) FM(PWM4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_11_8 FM(IRQ4) FM(QSTH_QHS) F_(0, 0) FM(DU_EXHSYNC_DU_HSYNC) FM(VI4_DATA4_B) F_(0, 0) F_(0, 0) FM(MSIOF3_RXD_E) F_(0, 0) FM(PWM5_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_15_12 FM(IRQ5) FM(QSTB_QHE) F_(0, 0) FM(DU_EXVSYNC_DU_VSYNC) FM(VI4_DATA5_B) FM(FSCLKST2_N_B) F_(0, 0) FM(MSIOF3_TXD_E) F_(0, 0) FM(PWM6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_19_16 FM(PWM0) FM(AVB_AVTP_PPS)F_(0, 0) F_(0, 0) FM(VI4_DATA6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IECLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_23_20 FM(PWM1_A) F_(0, 0) F_(0, 0) FM(HRX3_D) FM(VI4_DATA7_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IERX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_27_24 FM(PWM2_A) F_(0, 0) F_(0, 0) FM(HTX3_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IETX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1_31_28 FM(A0) FM(LCDOUT16) FM(MSIOF3_SYNC_B) F_(0, 0) FM(VI4_DATA8) F_(0, 0) FM(DU_DB0) F_(0, 0) F_(0, 0) FM(PWM3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2_3_0 FM(A1) FM(LCDOUT17) FM(MSIOF3_TXD_B) F_(0, 0) FM(VI4_DATA9) F_(0, 0) FM(DU_DB1) F_(0, 0) F_(0, 0) FM(PWM4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2_7_4 FM(A2) FM(LCDOUT18) FM(MSIOF3_SCK_B) F_(0, 0) FM(VI4_DATA10) F_(0, 0) FM(DU_DB2) F_(0, 0) F_(0, 0) FM(PWM5_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -652,7 +652,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_7_4, IRQ3), PINMUX_IPSR_GPSR(IP1_7_4, QSTVB_QVE), - PINMUX_IPSR_GPSR(IP1_7_4, A25), PINMUX_IPSR_GPSR(IP1_7_4, DU_DOTCLKOUT1), PINMUX_IPSR_MSEL(IP1_7_4, VI4_DATA3_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_7_4, PWM4_B, SEL_PWM4_1), @@ -660,7 +659,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_11_8, IRQ4), PINMUX_IPSR_GPSR(IP1_11_8, QSTH_QHS), - PINMUX_IPSR_GPSR(IP1_11_8, A24), PINMUX_IPSR_GPSR(IP1_11_8, DU_EXHSYNC_DU_HSYNC), PINMUX_IPSR_MSEL(IP1_11_8, VI4_DATA4_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_11_8, PWM5_B, SEL_PWM5_1), @@ -668,7 +666,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_15_12, IRQ5), PINMUX_IPSR_GPSR(IP1_15_12, QSTB_QHE), - PINMUX_IPSR_GPSR(IP1_15_12, A23), PINMUX_IPSR_GPSR(IP1_15_12, DU_EXVSYNC_DU_VSYNC), PINMUX_IPSR_MSEL(IP1_15_12, VI4_DATA5_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_15_12, PWM6_B, SEL_PWM6_1), @@ -677,18 +674,15 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_19_16, PWM0), PINMUX_IPSR_GPSR(IP1_19_16, AVB_AVTP_PPS), - PINMUX_IPSR_GPSR(IP1_19_16, A22), PINMUX_IPSR_MSEL(IP1_19_16, VI4_DATA6_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_19_16, IECLK_B, SEL_IEBUS_1), PINMUX_IPSR_MSEL(IP1_23_20, PWM1_A, SEL_PWM1_0), - PINMUX_IPSR_GPSR(IP1_23_20, A21), PINMUX_IPSR_MSEL(IP1_23_20, HRX3_D, SEL_HSCIF3_3), PINMUX_IPSR_MSEL(IP1_23_20, VI4_DATA7_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_23_20, IERX_B, SEL_IEBUS_1), PINMUX_IPSR_MSEL(IP1_27_24, PWM2_A, SEL_PWM2_0), - PINMUX_IPSR_GPSR(IP1_27_24, A20), PINMUX_IPSR_MSEL(IP1_27_24, HTX3_D, SEL_HSCIF3_3), PINMUX_IPSR_MSEL(IP1_27_24, IETX_B, SEL_IEBUS_1), -- cgit From fbd81e345c9393b96e8ad252eef390f8c6f9cf60 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Thu, 16 Nov 2017 12:17:18 +0900 Subject: pinctrl: sh-pfc: r8a7796: Fix to delete A20..A25 pins function definitions This patch fixes the macro definitions of A20..A25 pins function deleted. This is a correction because IPSR register specification for R8A7796 SoC was changed in R-Car Gen3 Hardware User's Manual Rev.0.53E. Fixes: f9aece7344bd81ce ("pinctrl: sh-pfc: Initial R8A7796 PFC support") Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Kaneko Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 73ed9c74c137..954daaef2ec3 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -224,12 +224,12 @@ #define IP0_27_24 FM(IRQ0) FM(QPOLB) F_(0, 0) FM(DU_CDE) FM(VI4_DATA0_B) FM(CAN0_TX_B) FM(CANFD0_TX_B) FM(MSIOF3_SS2_E) 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_31_28 FM(IRQ1) FM(QPOLA) F_(0, 0) FM(DU_DISP) FM(VI4_DATA1_B) FM(CAN0_RX_B) FM(CANFD0_RX_B) FM(MSIOF3_SS1_E) 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 IP1_3_0 FM(IRQ2) FM(QCPV_QDE) F_(0, 0) FM(DU_EXODDF_DU_ODDF_DISP_CDE) FM(VI4_DATA2_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SYNC_E) F_(0, 0) FM(PWM3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_7_4 FM(IRQ3) FM(QSTVB_QVE) FM(A25) FM(DU_DOTCLKOUT1) FM(VI4_DATA3_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SCK_E) F_(0, 0) FM(PWM4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_11_8 FM(IRQ4) FM(QSTH_QHS) FM(A24) FM(DU_EXHSYNC_DU_HSYNC) FM(VI4_DATA4_B) F_(0, 0) F_(0, 0) FM(MSIOF3_RXD_E) F_(0, 0) FM(PWM5_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_15_12 FM(IRQ5) FM(QSTB_QHE) FM(A23) FM(DU_EXVSYNC_DU_VSYNC) FM(VI4_DATA5_B) F_(0, 0) F_(0, 0) FM(MSIOF3_TXD_E) F_(0, 0) FM(PWM6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_19_16 FM(PWM0) FM(AVB_AVTP_PPS)FM(A22) F_(0, 0) FM(VI4_DATA6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IECLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_23_20 FM(PWM1_A) F_(0, 0) FM(A21) FM(HRX3_D) FM(VI4_DATA7_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IERX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_27_24 FM(PWM2_A) F_(0, 0) FM(A20) FM(HTX3_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IETX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_7_4 FM(IRQ3) FM(QSTVB_QVE) F_(0, 0) FM(DU_DOTCLKOUT1) FM(VI4_DATA3_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SCK_E) F_(0, 0) FM(PWM4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_11_8 FM(IRQ4) FM(QSTH_QHS) F_(0, 0) FM(DU_EXHSYNC_DU_HSYNC) FM(VI4_DATA4_B) F_(0, 0) F_(0, 0) FM(MSIOF3_RXD_E) F_(0, 0) FM(PWM5_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_15_12 FM(IRQ5) FM(QSTB_QHE) F_(0, 0) FM(DU_EXVSYNC_DU_VSYNC) FM(VI4_DATA5_B) F_(0, 0) F_(0, 0) FM(MSIOF3_TXD_E) F_(0, 0) FM(PWM6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_19_16 FM(PWM0) FM(AVB_AVTP_PPS)F_(0, 0) F_(0, 0) FM(VI4_DATA6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IECLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_23_20 FM(PWM1_A) F_(0, 0) F_(0, 0) FM(HRX3_D) FM(VI4_DATA7_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IERX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1_27_24 FM(PWM2_A) F_(0, 0) F_(0, 0) FM(HTX3_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IETX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1_31_28 FM(A0) FM(LCDOUT16) FM(MSIOF3_SYNC_B) F_(0, 0) FM(VI4_DATA8) F_(0, 0) FM(DU_DB0) F_(0, 0) F_(0, 0) FM(PWM3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2_3_0 FM(A1) FM(LCDOUT17) FM(MSIOF3_TXD_B) F_(0, 0) FM(VI4_DATA9) F_(0, 0) FM(DU_DB1) F_(0, 0) F_(0, 0) FM(PWM4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2_7_4 FM(A2) FM(LCDOUT18) FM(MSIOF3_SCK_B) F_(0, 0) FM(VI4_DATA10) F_(0, 0) FM(DU_DB2) F_(0, 0) F_(0, 0) FM(PWM5_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -654,7 +654,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_7_4, IRQ3), PINMUX_IPSR_GPSR(IP1_7_4, QSTVB_QVE), - PINMUX_IPSR_GPSR(IP1_7_4, A25), PINMUX_IPSR_GPSR(IP1_7_4, DU_DOTCLKOUT1), PINMUX_IPSR_MSEL(IP1_7_4, VI4_DATA3_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_7_4, PWM4_B, SEL_PWM4_1), @@ -662,7 +661,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_11_8, IRQ4), PINMUX_IPSR_GPSR(IP1_11_8, QSTH_QHS), - PINMUX_IPSR_GPSR(IP1_11_8, A24), PINMUX_IPSR_GPSR(IP1_11_8, DU_EXHSYNC_DU_HSYNC), PINMUX_IPSR_MSEL(IP1_11_8, VI4_DATA4_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_11_8, PWM5_B, SEL_PWM5_1), @@ -670,7 +668,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_15_12, IRQ5), PINMUX_IPSR_GPSR(IP1_15_12, QSTB_QHE), - PINMUX_IPSR_GPSR(IP1_15_12, A23), PINMUX_IPSR_GPSR(IP1_15_12, DU_EXVSYNC_DU_VSYNC), PINMUX_IPSR_MSEL(IP1_15_12, VI4_DATA5_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_15_12, PWM6_B, SEL_PWM6_1), @@ -678,18 +675,15 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1_19_16, PWM0), PINMUX_IPSR_GPSR(IP1_19_16, AVB_AVTP_PPS), - PINMUX_IPSR_GPSR(IP1_19_16, A22), PINMUX_IPSR_MSEL(IP1_19_16, VI4_DATA6_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_19_16, IECLK_B, SEL_IEBUS_1), PINMUX_IPSR_MSEL(IP1_23_20, PWM1_A, SEL_PWM1_0), - PINMUX_IPSR_GPSR(IP1_23_20, A21), PINMUX_IPSR_MSEL(IP1_23_20, HRX3_D, SEL_HSCIF3_3), PINMUX_IPSR_MSEL(IP1_23_20, VI4_DATA7_B, SEL_VIN4_1), PINMUX_IPSR_MSEL(IP1_23_20, IERX_B, SEL_IEBUS_1), PINMUX_IPSR_MSEL(IP1_27_24, PWM2_A, SEL_PWM2_0), - PINMUX_IPSR_GPSR(IP1_27_24, A20), PINMUX_IPSR_MSEL(IP1_27_24, HTX3_D, SEL_HSCIF3_3), PINMUX_IPSR_MSEL(IP1_27_24, IETX_B, SEL_IEBUS_1), -- cgit From 8714a9c1bdd388aa6cff6cd01e357c349300158e Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Thu, 16 Nov 2017 23:58:40 +0900 Subject: pinctrl: sh-pfc: r8a7795: Rename RTS{0,1,3,4}# pin function definitions This patch renames the pin function macro definitions of the GPSR and IPSR registers value for the RTS{0,1,3,4}# pin. This is a correction because GPSR and IPSR register specification for R8A7795 ES2.0 SoC was changed in R-Car Gen3 Hardware User's Manual Rev.0.54E. Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Kaneko [geert: Drop remaining "_TANS" from comments] Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795.c | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index a97256cd25df..7eddd0f2f847 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -158,11 +158,11 @@ #define GPSR5_11 F_(RX2_A, IP13_7_4) #define GPSR5_10 F_(TX2_A, IP13_3_0) #define GPSR5_9 F_(SCK2, IP12_31_28) -#define GPSR5_8 F_(RTS1_N_TANS, IP12_27_24) +#define GPSR5_8 F_(RTS1_N, IP12_27_24) #define GPSR5_7 F_(CTS1_N, IP12_23_20) #define GPSR5_6 F_(TX1_A, IP12_19_16) #define GPSR5_5 F_(RX1_A, IP12_15_12) -#define GPSR5_4 F_(RTS0_N_TANS, IP12_11_8) +#define GPSR5_4 F_(RTS0_N, IP12_11_8) #define GPSR5_3 F_(CTS0_N, IP12_7_4) #define GPSR5_2 F_(TX0, IP12_3_0) #define GPSR5_1 F_(RX0, IP11_31_28) @@ -215,7 +215,7 @@ #define IP0_11_8 FM(AVB_PHY_INT) F_(0, 0) FM(MSIOF2_SYNC_C) FM(RX4_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) #define IP0_15_12 FM(AVB_LINK) F_(0, 0) FM(MSIOF2_SCK_C) FM(TX4_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) #define IP0_19_16 FM(AVB_AVTP_MATCH_A) F_(0, 0) FM(MSIOF2_RXD_C) FM(CTS4_N_A) F_(0, 0) FM(FSCLKST2_N_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) -#define IP0_23_20 FM(AVB_AVTP_CAPTURE_A) F_(0, 0) FM(MSIOF2_TXD_C) FM(RTS4_N_TANS_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) +#define IP0_23_20 FM(AVB_AVTP_CAPTURE_A) F_(0, 0) FM(MSIOF2_TXD_C) FM(RTS4_N_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) #define IP0_27_24 FM(IRQ0) FM(QPOLB) F_(0, 0) FM(DU_CDE) FM(VI4_DATA0_B) FM(CAN0_TX_B) FM(CANFD0_TX_B) FM(MSIOF3_SS2_E) 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_31_28 FM(IRQ1) FM(QPOLA) F_(0, 0) FM(DU_DISP) FM(VI4_DATA1_B) FM(CAN0_RX_B) FM(CANFD0_RX_B) FM(MSIOF3_SS1_E) 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 IP1_3_0 FM(IRQ2) FM(QCPV_QDE) F_(0, 0) FM(DU_EXODDF_DU_ODDF_DISP_CDE) FM(VI4_DATA2_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SYNC_E) F_(0, 0) FM(PWM3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -237,7 +237,7 @@ #define IP2_27_24 FM(A7) FM(LCDOUT23) FM(MSIOF2_SS2_A) FM(TX4_B) FM(VI4_DATA15) FM(VI5_DATA15) FM(DU_DB7) F_(0, 0) 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 IP2_31_28 FM(A8) FM(RX3_B) FM(MSIOF2_SYNC_A) FM(HRX4_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(SDA6_A) FM(AVB_AVTP_MATCH_B) FM(PWM1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP3_3_0 FM(A9) F_(0, 0) FM(MSIOF2_SCK_A) FM(CTS4_N_B) F_(0, 0) FM(VI5_VSYNC_N) F_(0, 0) F_(0, 0) 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 IP3_7_4 FM(A10) F_(0, 0) FM(MSIOF2_RXD_A) FM(RTS4_N_TANS_B) F_(0, 0) FM(VI5_HSYNC_N) F_(0, 0) F_(0, 0) 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 IP3_7_4 FM(A10) F_(0, 0) FM(MSIOF2_RXD_A) FM(RTS4_N_B) F_(0, 0) FM(VI5_HSYNC_N) F_(0, 0) F_(0, 0) 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 IP3_11_8 FM(A11) FM(TX3_B) FM(MSIOF2_TXD_A) FM(HTX4_B) FM(HSCK4) FM(VI5_FIELD) F_(0, 0) FM(SCL6_A) FM(AVB_AVTP_CAPTURE_B) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP3_15_12 FM(A12) FM(LCDOUT12) FM(MSIOF3_SCK_C) F_(0, 0) FM(HRX4_A) FM(VI5_DATA8) FM(DU_DG4) F_(0, 0) 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 IP3_19_16 FM(A13) FM(LCDOUT13) FM(MSIOF3_SYNC_C) F_(0, 0) FM(HTX4_A) FM(VI5_DATA9) FM(DU_DG5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -253,7 +253,7 @@ #define IP4_27_24 FM(RD_N) F_(0, 0) FM(MSIOF3_SYNC_D) FM(RX3_A) FM(HRX3_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(CAN0_TX_A) FM(CANFD0_TX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP4_31_28 FM(RD_WR_N) F_(0, 0) FM(MSIOF3_RXD_D) FM(TX3_A) FM(HTX3_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(CAN0_RX_A) FM(CANFD0_RX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP5_3_0 FM(WE0_N) F_(0, 0) FM(MSIOF3_TXD_D) FM(CTS3_N) FM(HCTS3_N) F_(0, 0) F_(0, 0) FM(SCL6_B) FM(CAN_CLK) F_(0, 0) FM(IECLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP5_7_4 FM(WE1_N) F_(0, 0) FM(MSIOF3_SS1_D) FM(RTS3_N_TANS) FM(HRTS3_N) F_(0, 0) F_(0, 0) FM(SDA6_B) FM(CAN1_RX) FM(CANFD1_RX) FM(IERX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP5_7_4 FM(WE1_N) F_(0, 0) FM(MSIOF3_SS1_D) FM(RTS3_N) FM(HRTS3_N) F_(0, 0) F_(0, 0) FM(SDA6_B) FM(CAN1_RX) FM(CANFD1_RX) FM(IERX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP5_11_8 FM(EX_WAIT0_A) FM(QCLK) F_(0, 0) F_(0, 0) FM(VI4_CLK) F_(0, 0) FM(DU_DOTCLKOUT0) F_(0, 0) 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 IP5_15_12 FM(D0) FM(MSIOF2_SS1_B)FM(MSIOF3_SCK_A) F_(0, 0) FM(VI4_DATA16) FM(VI5_DATA0) F_(0, 0) F_(0, 0) 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 IP5_19_16 FM(D1) FM(MSIOF2_SS2_B)FM(MSIOF3_SYNC_A) F_(0, 0) FM(VI4_DATA17) FM(VI5_DATA1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -266,7 +266,7 @@ #define IP6_15_12 FM(D8) FM(LCDOUT0) FM(MSIOF2_SCK_D) FM(SCK4_C) FM(VI4_DATA0_A) F_(0, 0) FM(DU_DR0) F_(0, 0) 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 IP6_19_16 FM(D9) FM(LCDOUT1) FM(MSIOF2_SYNC_D) F_(0, 0) FM(VI4_DATA1_A) F_(0, 0) FM(DU_DR1) F_(0, 0) 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 IP6_23_20 FM(D10) FM(LCDOUT2) FM(MSIOF2_RXD_D) FM(HRX3_B) FM(VI4_DATA2_A) FM(CTS4_N_C) FM(DU_DR2) F_(0, 0) 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 IP6_27_24 FM(D11) FM(LCDOUT3) FM(MSIOF2_TXD_D) FM(HTX3_B) FM(VI4_DATA3_A) FM(RTS4_N_TANS_C)FM(DU_DR3) F_(0, 0) 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 IP6_27_24 FM(D11) FM(LCDOUT3) FM(MSIOF2_TXD_D) FM(HTX3_B) FM(VI4_DATA3_A) FM(RTS4_N_C) FM(DU_DR3) F_(0, 0) 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 IP6_31_28 FM(D12) FM(LCDOUT4) FM(MSIOF2_SS1_D) FM(RX4_C) FM(VI4_DATA4_A) F_(0, 0) FM(DU_DR4) F_(0, 0) 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 IP7_3_0 FM(D13) FM(LCDOUT5) FM(MSIOF2_SS2_D) FM(TX4_C) FM(VI4_DATA5_A) F_(0, 0) FM(DU_DR5) F_(0, 0) 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 IP7_7_4 FM(D14) FM(LCDOUT6) FM(MSIOF3_SS1_A) FM(HRX3_C) FM(VI4_DATA6_A) F_(0, 0) FM(DU_DR6) FM(SCL6_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) @@ -313,11 +313,11 @@ #define IP11_31_28 FM(RX0) FM(HRX1_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SCK0_C) FM(STP_ISCLK_0_C) FM(RIF0_D0_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) #define IP12_3_0 FM(TX0) FM(HTX1_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SPSYNC0_C)FM(STP_ISSYNC_0_C) FM(RIF0_D1_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) #define IP12_7_4 FM(CTS0_N) FM(HCTS1_N_B) FM(MSIOF1_SYNC_B) F_(0, 0) F_(0, 0) FM(TS_SPSYNC1_C)FM(STP_ISSYNC_1_C) FM(RIF1_SYNC_B) FM(AUDIO_CLKOUT_C) FM(ADICS_SAMP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_11_8 FM(RTS0_N_TANS) FM(HRTS1_N_B) FM(MSIOF1_SS1_B) FM(AUDIO_CLKA_B) FM(SCL2_A) F_(0, 0) FM(STP_IVCXO27_1_C) FM(RIF0_SYNC_B) F_(0, 0) FM(ADICHS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP12_11_8 FM(RTS0_N) FM(HRTS1_N_B) FM(MSIOF1_SS1_B) FM(AUDIO_CLKA_B) FM(SCL2_A) F_(0, 0) FM(STP_IVCXO27_1_C) FM(RIF0_SYNC_B) F_(0, 0) FM(ADICHS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP12_15_12 FM(RX1_A) FM(HRX1_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SDAT0_C) FM(STP_ISD_0_C) FM(RIF1_CLK_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) #define IP12_19_16 FM(TX1_A) FM(HTX1_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SDEN0_C) FM(STP_ISEN_0_C) FM(RIF1_D0_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) #define IP12_23_20 FM(CTS1_N) FM(HCTS1_N_A) FM(MSIOF1_RXD_B) F_(0, 0) F_(0, 0) FM(TS_SDEN1_C) FM(STP_ISEN_1_C) FM(RIF1_D0_B) F_(0, 0) FM(ADIDATA) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_27_24 FM(RTS1_N_TANS) FM(HRTS1_N_A) FM(MSIOF1_TXD_B) F_(0, 0) F_(0, 0) FM(TS_SDAT1_C) FM(STP_ISD_1_C) FM(RIF1_D1_B) F_(0, 0) FM(ADICHS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP12_27_24 FM(RTS1_N) FM(HRTS1_N_A) FM(MSIOF1_TXD_B) F_(0, 0) F_(0, 0) FM(TS_SDAT1_C) FM(STP_ISD_1_C) FM(RIF1_D1_B) F_(0, 0) FM(ADICHS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP12_31_28 FM(SCK2) FM(SCIF_CLK_B) FM(MSIOF1_SCK_B) F_(0, 0) F_(0, 0) FM(TS_SCK1_C) FM(STP_ISCLK_1_C) FM(RIF1_CLK_B) F_(0, 0) FM(ADICLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP13_3_0 FM(TX2_A) F_(0, 0) F_(0, 0) FM(SD2_CD_B) FM(SCL1_A) F_(0, 0) FM(FMCLK_A) FM(RIF1_D1_C) F_(0, 0) FM(FSO_CFE_0_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP13_7_4 FM(RX2_A) F_(0, 0) F_(0, 0) FM(SD2_WP_B) FM(SDA1_A) F_(0, 0) FM(FMIN_A) FM(RIF1_SYNC_C) F_(0, 0) FM(FSO_CFE_1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -624,7 +624,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP0_23_20, AVB_AVTP_CAPTURE_A, SEL_ETHERAVB_0), PINMUX_IPSR_MSEL(IP0_23_20, MSIOF2_TXD_C, SEL_MSIOF2_2), - PINMUX_IPSR_MSEL(IP0_23_20, RTS4_N_TANS_A, SEL_SCIF4_0), + PINMUX_IPSR_MSEL(IP0_23_20, RTS4_N_A, SEL_SCIF4_0), PINMUX_IPSR_GPSR(IP0_27_24, IRQ0), PINMUX_IPSR_GPSR(IP0_27_24, QPOLB), @@ -762,7 +762,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP3_7_4, A10), PINMUX_IPSR_MSEL(IP3_7_4, MSIOF2_RXD_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP3_7_4, RTS4_N_TANS_B, SEL_SCIF4_1), + PINMUX_IPSR_MSEL(IP3_7_4, RTS4_N_B, SEL_SCIF4_1), PINMUX_IPSR_GPSR(IP3_7_4, VI5_HSYNC_N), PINMUX_IPSR_GPSR(IP3_11_8, A11), @@ -865,7 +865,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP5_7_4, WE1_N), PINMUX_IPSR_MSEL(IP5_7_4, MSIOF3_SS1_D, SEL_MSIOF3_3), - PINMUX_IPSR_GPSR(IP5_7_4, RTS3_N_TANS), + PINMUX_IPSR_GPSR(IP5_7_4, RTS3_N), PINMUX_IPSR_GPSR(IP5_7_4, HRTS3_N), PINMUX_IPSR_MSEL(IP5_7_4, SDA6_B, SEL_I2C6_1), PINMUX_IPSR_GPSR(IP5_7_4, CAN1_RX), @@ -946,7 +946,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP6_27_24, MSIOF2_TXD_D, SEL_MSIOF2_3), PINMUX_IPSR_MSEL(IP6_27_24, HTX3_B, SEL_HSCIF3_1), PINMUX_IPSR_MSEL(IP6_27_24, VI4_DATA3_A, SEL_VIN4_0), - PINMUX_IPSR_MSEL(IP6_27_24, RTS4_N_TANS_C, SEL_SCIF4_2), + PINMUX_IPSR_MSEL(IP6_27_24, RTS4_N_C, SEL_SCIF4_2), PINMUX_IPSR_GPSR(IP6_27_24, DU_DR3), PINMUX_IPSR_GPSR(IP6_31_28, D12), @@ -1155,7 +1155,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP12_7_4, AUDIO_CLKOUT_C), PINMUX_IPSR_GPSR(IP12_7_4, ADICS_SAMP), - PINMUX_IPSR_GPSR(IP12_11_8, RTS0_N_TANS), + PINMUX_IPSR_GPSR(IP12_11_8, RTS0_N), PINMUX_IPSR_MSEL(IP12_11_8, HRTS1_N_B, SEL_HSCIF1_1), PINMUX_IPSR_MSEL(IP12_11_8, MSIOF1_SS1_B, SEL_MSIOF1_1), PINMUX_IPSR_MSEL(IP12_11_8, AUDIO_CLKA_B, SEL_ADG_A_1), @@ -1184,7 +1184,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP12_23_20, RIF1_D0_B, SEL_DRIF1_1), PINMUX_IPSR_GPSR(IP12_23_20, ADIDATA), - PINMUX_IPSR_GPSR(IP12_27_24, RTS1_N_TANS), + PINMUX_IPSR_GPSR(IP12_27_24, RTS1_N), PINMUX_IPSR_MSEL(IP12_27_24, HRTS1_N_A, SEL_HSCIF1_0), PINMUX_IPSR_MSEL(IP12_27_24, MSIOF1_TXD_B, SEL_MSIOF1_1), PINMUX_IPSR_MSEL(IP12_27_24, TS_SDAT1_C, SEL_TSIF1_2), @@ -3247,7 +3247,7 @@ static const unsigned int scif0_ctrl_pins[] = { RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 3), }; static const unsigned int scif0_ctrl_mux[] = { - RTS0_N_TANS_MARK, CTS0_N_MARK, + RTS0_N_MARK, CTS0_N_MARK, }; /* - SCIF1 ------------------------------------------------------------------ */ static const unsigned int scif1_data_a_pins[] = { @@ -3269,7 +3269,7 @@ static const unsigned int scif1_ctrl_pins[] = { RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 7), }; static const unsigned int scif1_ctrl_mux[] = { - RTS1_N_TANS_MARK, CTS1_N_MARK, + RTS1_N_MARK, CTS1_N_MARK, }; static const unsigned int scif1_data_b_pins[] = { @@ -3321,7 +3321,7 @@ static const unsigned int scif3_ctrl_pins[] = { RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25), }; static const unsigned int scif3_ctrl_mux[] = { - RTS3_N_TANS_MARK, CTS3_N_MARK, + RTS3_N_MARK, CTS3_N_MARK, }; static const unsigned int scif3_data_b_pins[] = { /* RX, TX */ @@ -3350,7 +3350,7 @@ static const unsigned int scif4_ctrl_a_pins[] = { RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13), }; static const unsigned int scif4_ctrl_a_mux[] = { - RTS4_N_TANS_A_MARK, CTS4_N_A_MARK, + RTS4_N_A_MARK, CTS4_N_A_MARK, }; static const unsigned int scif4_data_b_pins[] = { /* RX, TX */ @@ -3371,7 +3371,7 @@ static const unsigned int scif4_ctrl_b_pins[] = { RCAR_GP_PIN(1, 10), RCAR_GP_PIN(1, 9), }; static const unsigned int scif4_ctrl_b_mux[] = { - RTS4_N_TANS_B_MARK, CTS4_N_B_MARK, + RTS4_N_B_MARK, CTS4_N_B_MARK, }; static const unsigned int scif4_data_c_pins[] = { /* RX, TX */ @@ -3392,7 +3392,7 @@ static const unsigned int scif4_ctrl_c_pins[] = { RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 10), }; static const unsigned int scif4_ctrl_c_mux[] = { - RTS4_N_TANS_C_MARK, CTS4_N_C_MARK, + RTS4_N_C_MARK, CTS4_N_C_MARK, }; /* - SCIF5 ------------------------------------------------------------------ */ static const unsigned int scif5_data_a_pins[] = { @@ -5427,11 +5427,11 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(5, 3), 0, 3 }, /* CTS0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL18", 0xe6060348) { - { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0_TANS */ + { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0 */ { RCAR_GP_PIN(5, 5), 24, 3 }, /* RX1 */ { RCAR_GP_PIN(5, 6), 20, 3 }, /* TX1 */ { RCAR_GP_PIN(5, 7), 16, 3 }, /* CTS1 */ - { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1_TANS */ + { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1 */ { RCAR_GP_PIN(5, 9), 8, 3 }, /* SCK2 */ { RCAR_GP_PIN(5, 10), 4, 3 }, /* TX2 */ { RCAR_GP_PIN(5, 11), 0, 3 }, /* RX2 */ @@ -5676,11 +5676,11 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [13] = RCAR_GP_PIN(5, 1), /* RX0 */ [14] = RCAR_GP_PIN(5, 2), /* TX0 */ [15] = RCAR_GP_PIN(5, 3), /* CTS0_N */ - [16] = RCAR_GP_PIN(5, 4), /* RTS0_N_TANS */ + [16] = RCAR_GP_PIN(5, 4), /* RTS0_N */ [17] = RCAR_GP_PIN(5, 5), /* RX1_A */ [18] = RCAR_GP_PIN(5, 6), /* TX1_A */ [19] = RCAR_GP_PIN(5, 7), /* CTS1_N */ - [20] = RCAR_GP_PIN(5, 8), /* RTS1_N_TANS */ + [20] = RCAR_GP_PIN(5, 8), /* RTS1_N */ [21] = RCAR_GP_PIN(5, 9), /* SCK2 */ [22] = RCAR_GP_PIN(5, 10), /* TX2_A */ [23] = RCAR_GP_PIN(5, 11), /* RX2_A */ -- cgit From 0f4713d71f22d3b0ec3de6ae4a126cceecdea82b Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Thu, 16 Nov 2017 23:59:21 +0900 Subject: pinctrl: sh-pfc: r8a7796: Rename RTS{0,1,3,4}# pin function definitions This patch renames the pin function macro definitions of the GPSR5 and IPSR{0,3,5,6,12} registers value for the RTS{0,1,3,4}# pin. This is a correction because GPSR and IPSR register specification for R8A7796 SoC was changed in R-Car Gen3 Hardware User's Manual Rev.0.54E. Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Kaneko Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7796.c | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 954daaef2ec3..e5807d1ce0dc 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -163,11 +163,11 @@ #define GPSR5_11 F_(RX2_A, IP13_7_4) #define GPSR5_10 F_(TX2_A, IP13_3_0) #define GPSR5_9 F_(SCK2, IP12_31_28) -#define GPSR5_8 F_(RTS1_N_TANS, IP12_27_24) +#define GPSR5_8 F_(RTS1_N, IP12_27_24) #define GPSR5_7 F_(CTS1_N, IP12_23_20) #define GPSR5_6 F_(TX1_A, IP12_19_16) #define GPSR5_5 F_(RX1_A, IP12_15_12) -#define GPSR5_4 F_(RTS0_N_TANS, IP12_11_8) +#define GPSR5_4 F_(RTS0_N, IP12_11_8) #define GPSR5_3 F_(CTS0_N, IP12_7_4) #define GPSR5_2 F_(TX0, IP12_3_0) #define GPSR5_1 F_(RX0, IP11_31_28) @@ -220,7 +220,7 @@ #define IP0_11_8 FM(AVB_PHY_INT) F_(0, 0) FM(MSIOF2_SYNC_C) FM(RX4_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) #define IP0_15_12 FM(AVB_LINK) F_(0, 0) FM(MSIOF2_SCK_C) FM(TX4_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) #define IP0_19_16 FM(AVB_AVTP_MATCH_A) F_(0, 0) FM(MSIOF2_RXD_C) FM(CTS4_N_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) -#define IP0_23_20 FM(AVB_AVTP_CAPTURE_A) F_(0, 0) FM(MSIOF2_TXD_C) FM(RTS4_N_TANS_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) +#define IP0_23_20 FM(AVB_AVTP_CAPTURE_A) F_(0, 0) FM(MSIOF2_TXD_C) FM(RTS4_N_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) #define IP0_27_24 FM(IRQ0) FM(QPOLB) F_(0, 0) FM(DU_CDE) FM(VI4_DATA0_B) FM(CAN0_TX_B) FM(CANFD0_TX_B) FM(MSIOF3_SS2_E) 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_31_28 FM(IRQ1) FM(QPOLA) F_(0, 0) FM(DU_DISP) FM(VI4_DATA1_B) FM(CAN0_RX_B) FM(CANFD0_RX_B) FM(MSIOF3_SS1_E) 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 IP1_3_0 FM(IRQ2) FM(QCPV_QDE) F_(0, 0) FM(DU_EXODDF_DU_ODDF_DISP_CDE) FM(VI4_DATA2_B) F_(0, 0) F_(0, 0) FM(MSIOF3_SYNC_E) F_(0, 0) FM(PWM3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -240,7 +240,7 @@ #define IP2_27_24 FM(A7) FM(LCDOUT23) FM(MSIOF2_SS2_A) FM(TX4_B) FM(VI4_DATA15) FM(VI5_DATA15) FM(DU_DB7) F_(0, 0) 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 IP2_31_28 FM(A8) FM(RX3_B) FM(MSIOF2_SYNC_A) FM(HRX4_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(SDA6_A) FM(AVB_AVTP_MATCH_B) FM(PWM1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP3_3_0 FM(A9) F_(0, 0) FM(MSIOF2_SCK_A) FM(CTS4_N_B) F_(0, 0) FM(VI5_VSYNC_N) F_(0, 0) F_(0, 0) 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 IP3_7_4 FM(A10) F_(0, 0) FM(MSIOF2_RXD_A) FM(RTS4_N_TANS_B) F_(0, 0) FM(VI5_HSYNC_N) F_(0, 0) F_(0, 0) 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 IP3_7_4 FM(A10) F_(0, 0) FM(MSIOF2_RXD_A) FM(RTS4_N_B) F_(0, 0) FM(VI5_HSYNC_N) F_(0, 0) F_(0, 0) 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 IP3_11_8 FM(A11) FM(TX3_B) FM(MSIOF2_TXD_A) FM(HTX4_B) FM(HSCK4) FM(VI5_FIELD) F_(0, 0) FM(SCL6_A) FM(AVB_AVTP_CAPTURE_B) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ @@ -258,7 +258,7 @@ #define IP4_27_24 FM(RD_N) F_(0, 0) FM(MSIOF3_SYNC_D) FM(RX3_A) FM(HRX3_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(CAN0_TX_A) FM(CANFD0_TX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP4_31_28 FM(RD_WR_N) F_(0, 0) FM(MSIOF3_RXD_D) FM(TX3_A) FM(HTX3_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(CAN0_RX_A) FM(CANFD0_RX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP5_3_0 FM(WE0_N) F_(0, 0) FM(MSIOF3_TXD_D) FM(CTS3_N) FM(HCTS3_N) F_(0, 0) F_(0, 0) FM(SCL6_B) FM(CAN_CLK) F_(0, 0) FM(IECLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP5_7_4 FM(WE1_N) F_(0, 0) FM(MSIOF3_SS1_D) FM(RTS3_N_TANS) FM(HRTS3_N) F_(0, 0) F_(0, 0) FM(SDA6_B) FM(CAN1_RX) FM(CANFD1_RX) FM(IERX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP5_7_4 FM(WE1_N) F_(0, 0) FM(MSIOF3_SS1_D) FM(RTS3_N) FM(HRTS3_N) F_(0, 0) F_(0, 0) FM(SDA6_B) FM(CAN1_RX) FM(CANFD1_RX) FM(IERX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP5_11_8 FM(EX_WAIT0_A) FM(QCLK) F_(0, 0) F_(0, 0) FM(VI4_CLK) F_(0, 0) FM(DU_DOTCLKOUT0) F_(0, 0) 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 IP5_15_12 FM(D0) FM(MSIOF2_SS1_B)FM(MSIOF3_SCK_A) F_(0, 0) FM(VI4_DATA16) FM(VI5_DATA0) F_(0, 0) F_(0, 0) 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 IP5_19_16 FM(D1) FM(MSIOF2_SS2_B)FM(MSIOF3_SYNC_A) F_(0, 0) FM(VI4_DATA17) FM(VI5_DATA1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -271,7 +271,7 @@ #define IP6_15_12 FM(D8) FM(LCDOUT0) FM(MSIOF2_SCK_D) FM(SCK4_C) FM(VI4_DATA0_A) F_(0, 0) FM(DU_DR0) F_(0, 0) 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 IP6_19_16 FM(D9) FM(LCDOUT1) FM(MSIOF2_SYNC_D) F_(0, 0) FM(VI4_DATA1_A) F_(0, 0) FM(DU_DR1) F_(0, 0) 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 IP6_23_20 FM(D10) FM(LCDOUT2) FM(MSIOF2_RXD_D) FM(HRX3_B) FM(VI4_DATA2_A) FM(CTS4_N_C) FM(DU_DR2) F_(0, 0) 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 IP6_27_24 FM(D11) FM(LCDOUT3) FM(MSIOF2_TXD_D) FM(HTX3_B) FM(VI4_DATA3_A) FM(RTS4_N_TANS_C)FM(DU_DR3) F_(0, 0) 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 IP6_27_24 FM(D11) FM(LCDOUT3) FM(MSIOF2_TXD_D) FM(HTX3_B) FM(VI4_DATA3_A) FM(RTS4_N_C) FM(DU_DR3) F_(0, 0) 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 IP6_31_28 FM(D12) FM(LCDOUT4) FM(MSIOF2_SS1_D) FM(RX4_C) FM(VI4_DATA4_A) F_(0, 0) FM(DU_DR4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ @@ -318,11 +318,11 @@ #define IP11_31_28 FM(RX0) FM(HRX1_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SCK0_C) FM(STP_ISCLK_0_C) FM(RIF0_D0_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) #define IP12_3_0 FM(TX0) FM(HTX1_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SPSYNC0_C)FM(STP_ISSYNC_0_C) FM(RIF0_D1_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) #define IP12_7_4 FM(CTS0_N) FM(HCTS1_N_B) FM(MSIOF1_SYNC_B) F_(0, 0) F_(0, 0) FM(TS_SPSYNC1_C)FM(STP_ISSYNC_1_C) FM(RIF1_SYNC_B) FM(AUDIO_CLKOUT_C) FM(ADICS_SAMP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_11_8 FM(RTS0_N_TANS) FM(HRTS1_N_B) FM(MSIOF1_SS1_B) FM(AUDIO_CLKA_B) FM(SCL2_A) F_(0, 0) FM(STP_IVCXO27_1_C) FM(RIF0_SYNC_B) F_(0, 0) FM(ADICHS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP12_11_8 FM(RTS0_N) FM(HRTS1_N_B) FM(MSIOF1_SS1_B) FM(AUDIO_CLKA_B) FM(SCL2_A) F_(0, 0) FM(STP_IVCXO27_1_C) FM(RIF0_SYNC_B) F_(0, 0) FM(ADICHS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP12_15_12 FM(RX1_A) FM(HRX1_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SDAT0_C) FM(STP_ISD_0_C) FM(RIF1_CLK_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) #define IP12_19_16 FM(TX1_A) FM(HTX1_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SDEN0_C) FM(STP_ISEN_0_C) FM(RIF1_D0_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) #define IP12_23_20 FM(CTS1_N) FM(HCTS1_N_A) FM(MSIOF1_RXD_B) F_(0, 0) F_(0, 0) FM(TS_SDEN1_C) FM(STP_ISEN_1_C) FM(RIF1_D0_B) F_(0, 0) FM(ADIDATA) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_27_24 FM(RTS1_N_TANS) FM(HRTS1_N_A) FM(MSIOF1_TXD_B) F_(0, 0) F_(0, 0) FM(TS_SDAT1_C) FM(STP_ISD_1_C) FM(RIF1_D1_B) F_(0, 0) FM(ADICHS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP12_27_24 FM(RTS1_N) FM(HRTS1_N_A) FM(MSIOF1_TXD_B) F_(0, 0) F_(0, 0) FM(TS_SDAT1_C) FM(STP_ISD_1_C) FM(RIF1_D1_B) F_(0, 0) FM(ADICHS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP12_31_28 FM(SCK2) FM(SCIF_CLK_B) FM(MSIOF1_SCK_B) F_(0, 0) F_(0, 0) FM(TS_SCK1_C) FM(STP_ISCLK_1_C) FM(RIF1_CLK_B) F_(0, 0) FM(ADICLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP13_3_0 FM(TX2_A) F_(0, 0) F_(0, 0) FM(SD2_CD_B) FM(SCL1_A) F_(0, 0) FM(FMCLK_A) FM(RIF1_D1_C) F_(0, 0) FM(FSO_CFE_0_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP13_7_4 FM(RX2_A) F_(0, 0) F_(0, 0) FM(SD2_WP_B) FM(SDA1_A) F_(0, 0) FM(FMIN_A) FM(RIF1_SYNC_C) F_(0, 0) FM(FSO_CFE_1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -626,7 +626,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP0_23_20, AVB_AVTP_CAPTURE_A, SEL_ETHERAVB_0), PINMUX_IPSR_MSEL(IP0_23_20, MSIOF2_TXD_C, SEL_MSIOF2_2), - PINMUX_IPSR_MSEL(IP0_23_20, RTS4_N_TANS_A, SEL_SCIF4_0), + PINMUX_IPSR_MSEL(IP0_23_20, RTS4_N_A, SEL_SCIF4_0), PINMUX_IPSR_GPSR(IP0_27_24, IRQ0), PINMUX_IPSR_GPSR(IP0_27_24, QPOLB), @@ -763,7 +763,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP3_7_4, A10), PINMUX_IPSR_MSEL(IP3_7_4, MSIOF2_RXD_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP3_7_4, RTS4_N_TANS_B, SEL_SCIF4_1), + PINMUX_IPSR_MSEL(IP3_7_4, RTS4_N_B, SEL_SCIF4_1), PINMUX_IPSR_GPSR(IP3_7_4, VI5_HSYNC_N), PINMUX_IPSR_GPSR(IP3_11_8, A11), @@ -866,7 +866,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP5_7_4, WE1_N), PINMUX_IPSR_MSEL(IP5_7_4, MSIOF3_SS1_D, SEL_MSIOF3_3), - PINMUX_IPSR_GPSR(IP5_7_4, RTS3_N_TANS), + PINMUX_IPSR_GPSR(IP5_7_4, RTS3_N), PINMUX_IPSR_GPSR(IP5_7_4, HRTS3_N), PINMUX_IPSR_MSEL(IP5_7_4, SDA6_B, SEL_I2C6_1), PINMUX_IPSR_GPSR(IP5_7_4, CAN1_RX), @@ -947,7 +947,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP6_27_24, MSIOF2_TXD_D, SEL_MSIOF2_3), PINMUX_IPSR_MSEL(IP6_27_24, HTX3_B, SEL_HSCIF3_1), PINMUX_IPSR_MSEL(IP6_27_24, VI4_DATA3_A, SEL_VIN4_0), - PINMUX_IPSR_MSEL(IP6_27_24, RTS4_N_TANS_C, SEL_SCIF4_2), + PINMUX_IPSR_MSEL(IP6_27_24, RTS4_N_C, SEL_SCIF4_2), PINMUX_IPSR_GPSR(IP6_27_24, DU_DR3), PINMUX_IPSR_GPSR(IP6_31_28, D12), @@ -1155,7 +1155,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP12_7_4, AUDIO_CLKOUT_C), PINMUX_IPSR_GPSR(IP12_7_4, ADICS_SAMP), - PINMUX_IPSR_GPSR(IP12_11_8, RTS0_N_TANS), + PINMUX_IPSR_GPSR(IP12_11_8, RTS0_N), PINMUX_IPSR_MSEL(IP12_11_8, HRTS1_N_B, SEL_HSCIF1_1), PINMUX_IPSR_MSEL(IP12_11_8, MSIOF1_SS1_B, SEL_MSIOF1_1), PINMUX_IPSR_MSEL(IP12_11_8, AUDIO_CLKA_B, SEL_ADG_A_1), @@ -1184,7 +1184,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP12_23_20, RIF1_D0_B, SEL_DRIF1_1), PINMUX_IPSR_GPSR(IP12_23_20, ADIDATA), - PINMUX_IPSR_GPSR(IP12_27_24, RTS1_N_TANS), + PINMUX_IPSR_GPSR(IP12_27_24, RTS1_N), PINMUX_IPSR_MSEL(IP12_27_24, HRTS1_N_A, SEL_HSCIF1_0), PINMUX_IPSR_MSEL(IP12_27_24, MSIOF1_TXD_B, SEL_MSIOF1_1), PINMUX_IPSR_MSEL(IP12_27_24, TS_SDAT1_C, SEL_TSIF1_2), @@ -3249,7 +3249,7 @@ static const unsigned int scif0_ctrl_pins[] = { RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 3), }; static const unsigned int scif0_ctrl_mux[] = { - RTS0_N_TANS_MARK, CTS0_N_MARK, + RTS0_N_MARK, CTS0_N_MARK, }; /* - SCIF1 ------------------------------------------------------------------ */ static const unsigned int scif1_data_a_pins[] = { @@ -3271,7 +3271,7 @@ static const unsigned int scif1_ctrl_pins[] = { RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 7), }; static const unsigned int scif1_ctrl_mux[] = { - RTS1_N_TANS_MARK, CTS1_N_MARK, + RTS1_N_MARK, CTS1_N_MARK, }; static const unsigned int scif1_data_b_pins[] = { @@ -3323,7 +3323,7 @@ static const unsigned int scif3_ctrl_pins[] = { RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25), }; static const unsigned int scif3_ctrl_mux[] = { - RTS3_N_TANS_MARK, CTS3_N_MARK, + RTS3_N_MARK, CTS3_N_MARK, }; static const unsigned int scif3_data_b_pins[] = { /* RX, TX */ @@ -3352,7 +3352,7 @@ static const unsigned int scif4_ctrl_a_pins[] = { RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13), }; static const unsigned int scif4_ctrl_a_mux[] = { - RTS4_N_TANS_A_MARK, CTS4_N_A_MARK, + RTS4_N_A_MARK, CTS4_N_A_MARK, }; static const unsigned int scif4_data_b_pins[] = { /* RX, TX */ @@ -3373,7 +3373,7 @@ static const unsigned int scif4_ctrl_b_pins[] = { RCAR_GP_PIN(1, 10), RCAR_GP_PIN(1, 9), }; static const unsigned int scif4_ctrl_b_mux[] = { - RTS4_N_TANS_B_MARK, CTS4_N_B_MARK, + RTS4_N_B_MARK, CTS4_N_B_MARK, }; static const unsigned int scif4_data_c_pins[] = { /* RX, TX */ @@ -3394,7 +3394,7 @@ static const unsigned int scif4_ctrl_c_pins[] = { RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 10), }; static const unsigned int scif4_ctrl_c_mux[] = { - RTS4_N_TANS_C_MARK, CTS4_N_C_MARK, + RTS4_N_C_MARK, CTS4_N_C_MARK, }; /* - SCIF5 ------------------------------------------------------------------ */ static const unsigned int scif5_data_a_pins[] = { @@ -5400,11 +5400,11 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(5, 3), 0, 3 }, /* CTS0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL18", 0xe6060348) { - { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0_TANS */ + { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0 */ { RCAR_GP_PIN(5, 5), 24, 3 }, /* RX1 */ { RCAR_GP_PIN(5, 6), 20, 3 }, /* TX1 */ { RCAR_GP_PIN(5, 7), 16, 3 }, /* CTS1 */ - { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1_TANS */ + { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1 */ { RCAR_GP_PIN(5, 9), 8, 3 }, /* SCK2 */ { RCAR_GP_PIN(5, 10), 4, 3 }, /* TX2 */ { RCAR_GP_PIN(5, 11), 0, 3 }, /* RX2 */ @@ -5649,11 +5649,11 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [13] = RCAR_GP_PIN(5, 1), /* RX0 */ [14] = RCAR_GP_PIN(5, 2), /* TX0 */ [15] = RCAR_GP_PIN(5, 3), /* CTS0_N */ - [16] = RCAR_GP_PIN(5, 4), /* RTS0_N_TANS */ + [16] = RCAR_GP_PIN(5, 4), /* RTS0_N */ [17] = RCAR_GP_PIN(5, 5), /* RX1_A */ [18] = RCAR_GP_PIN(5, 6), /* TX1_A */ [19] = RCAR_GP_PIN(5, 7), /* CTS1_N */ - [20] = RCAR_GP_PIN(5, 8), /* RTS1_N_TANS */ + [20] = RCAR_GP_PIN(5, 8), /* RTS1_N */ [21] = RCAR_GP_PIN(5, 9), /* SCK2 */ [22] = RCAR_GP_PIN(5, 10), /* TX2_A */ [23] = RCAR_GP_PIN(5, 11), /* RX2_A */ -- cgit From c45985d359c40899ef05e44bb24a63241afaec10 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Fri, 17 Nov 2017 11:41:23 +0100 Subject: pinctrl: sh-pfc: r8a77995: Add CAN support This patch adds CAN[0-1] pinmux support to the r8a77995 SoC. Signed-off-by: Ulrich Hecht Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a77995.c | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c index 2c9a71a59fc3..c4ea718e172e 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c @@ -1059,6 +1059,45 @@ static const unsigned int avb0_avtp_capture_b_mux[] = { AVB0_AVTP_CAPTURE_B_MARK, }; +/* - CAN ------------------------------------------------------------------ */ +static const unsigned int can0_data_a_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 31), +}; +static const unsigned int can0_data_a_mux[] = { + CAN0_TX_A_MARK, CAN0_RX_A_MARK, +}; +static const unsigned int can0_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(4, 22), RCAR_GP_PIN(4, 5), +}; +static const unsigned int can0_data_b_mux[] = { + CAN0_TX_B_MARK, CAN0_RX_B_MARK, +}; +static const unsigned int can1_data_a_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(4, 30), RCAR_GP_PIN(4, 29), +}; +static const unsigned int can1_data_a_mux[] = { + CAN1_TX_A_MARK, CAN1_RX_A_MARK, +}; +static const unsigned int can1_data_b_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(4, 7), RCAR_GP_PIN(4, 6), +}; +static const unsigned int can1_data_b_mux[] = { + CAN1_TX_B_MARK, CAN1_RX_B_MARK, +}; + +/* - CAN Clock -------------------------------------------------------------- */ +static const unsigned int can_clk_pins[] = { + /* CLK */ + RCAR_GP_PIN(5, 2), +}; +static const unsigned int can_clk_mux[] = { + CAN_CLK_MARK, +}; + /* - I2C -------------------------------------------------------------------- */ static const unsigned int i2c0_pins[] = { /* SCL, SDA */ @@ -1506,6 +1545,11 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb0_avtp_pps_b), SH_PFC_PIN_GROUP(avb0_avtp_match_b), SH_PFC_PIN_GROUP(avb0_avtp_capture_b), + SH_PFC_PIN_GROUP(can0_data_a), + SH_PFC_PIN_GROUP(can0_data_b), + SH_PFC_PIN_GROUP(can1_data_a), + SH_PFC_PIN_GROUP(can1_data_b), + SH_PFC_PIN_GROUP(can_clk), SH_PFC_PIN_GROUP(i2c0), SH_PFC_PIN_GROUP(i2c1), SH_PFC_PIN_GROUP(i2c2_a), @@ -1583,6 +1627,18 @@ static const char * const avb0_groups[] = { "avb0_avtp_capture_b", }; +static const char * const can0_groups[] = { + "can0_data_a", + "can0_data_b", +}; +static const char * const can1_groups[] = { + "can1_data_a", + "can1_data_b", +}; +static const char * const can_clk_groups[] = { + "can_clk", +}; + static const char * const i2c0_groups[] = { "i2c0", }; @@ -1693,6 +1749,9 @@ static const char * const usb0_groups[] = { static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(audio_clk), SH_PFC_FUNCTION(avb0), + SH_PFC_FUNCTION(can0), + SH_PFC_FUNCTION(can1), + SH_PFC_FUNCTION(can_clk), SH_PFC_FUNCTION(i2c0), SH_PFC_FUNCTION(i2c1), SH_PFC_FUNCTION(i2c2), -- cgit From 527890f72892b127b67567af6bdbdc5288c211c1 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Fri, 17 Nov 2017 11:41:24 +0100 Subject: pinctrl: sh-pfc: r8a77995: Add CAN FD support This patch adds CAN FD[0-1] pinmux support to the r8a77995 SoC. Signed-off-by: Ulrich Hecht Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a77995.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c index c4ea718e172e..a4927b78a17b 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c @@ -1098,6 +1098,22 @@ static const unsigned int can_clk_mux[] = { CAN_CLK_MARK, }; +/* - CAN FD ----------------------------------------------------------------- */ +static const unsigned int canfd0_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 31), +}; +static const unsigned int canfd0_data_mux[] = { + CANFD0_TX_MARK, CANFD0_RX_MARK, +}; +static const unsigned int canfd1_data_pins[] = { + /* TX, RX */ + RCAR_GP_PIN(4, 30), RCAR_GP_PIN(4, 29), +}; +static const unsigned int canfd1_data_mux[] = { + CANFD1_TX_MARK, CANFD1_RX_MARK, +}; + /* - I2C -------------------------------------------------------------------- */ static const unsigned int i2c0_pins[] = { /* SCL, SDA */ @@ -1550,6 +1566,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(can1_data_a), SH_PFC_PIN_GROUP(can1_data_b), SH_PFC_PIN_GROUP(can_clk), + SH_PFC_PIN_GROUP(canfd0_data), + SH_PFC_PIN_GROUP(canfd1_data), SH_PFC_PIN_GROUP(i2c0), SH_PFC_PIN_GROUP(i2c1), SH_PFC_PIN_GROUP(i2c2_a), @@ -1639,6 +1657,13 @@ static const char * const can_clk_groups[] = { "can_clk", }; +static const char * const canfd0_groups[] = { + "canfd0_data", +}; +static const char * const canfd1_groups[] = { + "canfd1_data", +}; + static const char * const i2c0_groups[] = { "i2c0", }; @@ -1752,6 +1777,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(can0), SH_PFC_FUNCTION(can1), SH_PFC_FUNCTION(can_clk), + SH_PFC_FUNCTION(canfd0), + SH_PFC_FUNCTION(canfd1), SH_PFC_FUNCTION(i2c0), SH_PFC_FUNCTION(i2c1), SH_PFC_FUNCTION(i2c2), -- cgit From ad63da85f45fa55c270e5681e9b985605ec51f8d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 2 Dec 2017 12:23:09 +0100 Subject: pinctrl: gemini: Support drive strength setting The Gemini pin controller can set drive strength for a few select groups of pins (not individually). Implement this for GMAC0 and 1 (ethernet ports), IDE and PCI. Cc: devicetree@vger.kernel.org Reviewed-by: Rob Herring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-gemini.c | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-gemini.c b/drivers/pinctrl/pinctrl-gemini.c index 10f8f3a35fe1..5e789753f945 100644 --- a/drivers/pinctrl/pinctrl-gemini.c +++ b/drivers/pinctrl/pinctrl-gemini.c @@ -67,6 +67,9 @@ struct gemini_pmx { * elements in .pins so we can iterate over that array * @mask: bits to clear to enable this when doing pin muxing * @value: bits to set to enable this when doing pin muxing + * @driving_mask: bitmask for the IO Pad driving register for this + * group, if it supports altering the driving strength of + * its lines. */ struct gemini_pin_group { const char *name; @@ -74,12 +77,14 @@ struct gemini_pin_group { const unsigned int num_pins; u32 mask; u32 value; + u32 driving_mask; }; /* Some straight-forward control registers */ #define GLOBAL_WORD_ID 0x00 #define GLOBAL_STATUS 0x04 #define GLOBAL_STATUS_FLPIN BIT(20) +#define GLOBAL_IODRIVE 0x10 #define GLOBAL_GMAC_CTRL_SKEW 0x1c #define GLOBAL_GMAC0_DATA_SKEW 0x20 #define GLOBAL_GMAC1_DATA_SKEW 0x24 @@ -738,6 +743,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = { /* Conflict with all flash usage */ .value = IDE_PADS_ENABLE | NAND_PADS_DISABLE | PFLASH_PADS_DISABLE | SFLASH_PADS_DISABLE, + .driving_mask = GENMASK(21, 20), }, { .name = "satagrp", @@ -753,6 +759,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = { .name = "gmii_gmac0_grp", .pins = gmii_gmac0_3512_pins, .num_pins = ARRAY_SIZE(gmii_gmac0_3512_pins), + .driving_mask = GENMASK(17, 16), }, { .name = "gmii_gmac1_grp", @@ -760,6 +767,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = { .num_pins = ARRAY_SIZE(gmii_gmac1_3512_pins), /* Bring out RGMII on the GMAC1 pins */ .value = GEMINI_GMAC_IOSEL_GMAC0_GMAC1_RGMII, + .driving_mask = GENMASK(19, 18), }, { .name = "pcigrp", @@ -767,6 +775,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = { .num_pins = ARRAY_SIZE(pci_3512_pins), /* Conflict only with GPIO2 */ .value = PCI_PADS_ENABLE | PCI_CLK_PAD_ENABLE, + .driving_mask = GENMASK(23, 22), }, { .name = "lpcgrp", @@ -1671,6 +1680,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = { /* Conflict with all flash usage */ .value = IDE_PADS_ENABLE | NAND_PADS_DISABLE | PFLASH_PADS_DISABLE | SFLASH_PADS_DISABLE, + .driving_mask = GENMASK(21, 20), }, { .name = "satagrp", @@ -1686,6 +1696,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = { .name = "gmii_gmac0_grp", .pins = gmii_gmac0_3516_pins, .num_pins = ARRAY_SIZE(gmii_gmac0_3516_pins), + .driving_mask = GENMASK(17, 16), }, { .name = "gmii_gmac1_grp", @@ -1693,6 +1704,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = { .num_pins = ARRAY_SIZE(gmii_gmac1_3516_pins), /* Bring out RGMII on the GMAC1 pins */ .value = GEMINI_GMAC_IOSEL_GMAC0_GMAC1_RGMII, + .driving_mask = GENMASK(19, 18), }, { .name = "pcigrp", @@ -1700,6 +1712,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = { .num_pins = ARRAY_SIZE(pci_3516_pins), /* Conflict only with GPIO2 */ .value = PCI_PADS_ENABLE | PCI_CLK_PAD_ENABLE, + .driving_mask = GENMASK(23, 22), }, { .name = "lpcgrp", @@ -2394,9 +2407,77 @@ static int gemini_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, return ret; } +static int gemini_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned long *configs, + unsigned num_configs) +{ + struct gemini_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct gemini_pin_group *grp = NULL; + enum pin_config_param param; + u32 arg; + u32 val; + int i; + + if (pmx->is_3512) + grp = &gemini_3512_pin_groups[selector]; + if (pmx->is_3516) + grp = &gemini_3516_pin_groups[selector]; + + /* First figure out if this group supports configs */ + if (!grp->driving_mask) { + dev_err(pmx->dev, "pin config group \"%s\" does " + "not support drive strength setting\n", + grp->name); + return -EINVAL; + } + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_DRIVE_STRENGTH: + switch (arg) { + case 4: + val = 0; + break; + case 8: + val = 1; + break; + case 12: + val = 2; + break; + case 16: + val = 3; + break; + default: + dev_err(pmx->dev, + "invalid drive strength %d mA\n", + arg); + return -ENOTSUPP; + } + val <<= (ffs(grp->driving_mask) - 1); + regmap_update_bits(pmx->map, GLOBAL_IODRIVE, + grp->driving_mask, + val); + dev_info(pmx->dev, + "set group %s to %d mA drive strength mask %08x val %08x\n", + grp->name, arg, grp->driving_mask, val); + break; + default: + dev_err(pmx->dev, "invalid config param %04x\n", param); + return -ENOTSUPP; + } + } + + return 0; +} + static const struct pinconf_ops gemini_pinconf_ops = { .pin_config_get = gemini_pinconf_get, .pin_config_set = gemini_pinconf_set, + .pin_config_group_set = gemini_pinconf_group_set, .is_generic = true, }; -- cgit From 33b6cb58cbb6c872ebf874d8017c27aaa2130928 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 4 Dec 2017 17:08:15 +0000 Subject: pinctrl: intel: ensure error return ret is initialized In the (unlikely) event that community->ngpps is zero, or if every gpp->gpio_base is less than zero, then an ininitialized value in ret is returned by function intel_gpio_add_pin_ranges. Fix this by ensuring ret is initialized to zero. It's a moot point, but I think it is worthwhile ensuring this corner case is fixed. Detected by CoverityScan, CID#1462415 ("Uninitialized scalar variable") Fixes: a60eac3239f0 ("pinctrl: intel: Allow custom GPIO base for pad groups") Signed-off-by: Colin Ian King Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 359800fcb951..96e73e30204e 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1083,7 +1083,7 @@ static struct irq_chip intel_gpio_irqchip = { static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl, const struct intel_community *community) { - int ret, i; + int ret = 0, i; for (i = 0; i < community->ngpps; i++) { const struct intel_padgroup *gpp = &community->gpps[i]; -- cgit From 4c3c9a9d0d97b29ed290d342177eeb13cd649189 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 4 Dec 2017 13:31:54 +0100 Subject: i2c: imx: use proper GPIO directions for recovery When converting to GPIOD, the GPIO directions of SCL/SDA have been swapped. Fix it! Fixes: ad36a27959cabb ("i2c: imx: switch to using gpiod for bus recovery gpios") Signed-off-by: Wolfram Sang Reviewed-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index c4cf26571b66..6c0d59ddf5b6 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1006,8 +1006,8 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, PINCTRL_STATE_DEFAULT); i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, "gpio"); - rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_OUT_HIGH); - rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_IN); + rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); + rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH); if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER || PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) { -- cgit From 608c0d8804ef3ca4cda8ec6ad914e47deb283d7b Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Thu, 9 Nov 2017 08:00:35 -0600 Subject: PCI/IOV: Add pci_vf_drivers_autoprobe() interface Add a pci_vf_drivers_autoprobe() interface. Setting autoprobe to false on the PF prevents drivers from binding to VFs when they are enabled. Signed-off-by: Bryant G. Ly Signed-off-by: Juan J. Alvarez Acked-by: Bjorn Helgaas Acked-by: Russell Currey Reviewed-by: Alexey Kardashevskiy Signed-off-by: Michael Ellerman --- drivers/pci/iov.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 6bacb8995e96..0b7b5da63d4e 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -635,6 +635,17 @@ void pci_restore_iov_state(struct pci_dev *dev) sriov_restore_state(dev); } +/** + * pci_vf_drivers_autoprobe - set PF property drivers_autoprobe for VFs + * @dev: the PCI device + * @auto_probe: set VF drivers auto probe flag + */ +void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool auto_probe) +{ + if (dev->is_physfn) + dev->sriov->drivers_autoprobe = auto_probe; +} + /** * pci_iov_bus_range - find bus range used by Virtual Function * @bus: the PCI bus -- cgit From 7d42762d8cdff2974c3cfddeb480d467018f55fe Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Dec 2017 14:35:35 +0100 Subject: i2c: imx: Include the right GPIO header is not used in this file, by is. Someone is just lucky with their implicit includes. Signed-off-by: Linus Walleij Reviewed-by: Fabio Estevam Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 6c0d59ddf5b6..999557729ad2 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #include #include #include -- cgit From d72ebbcc446086cbc1116f83d6da063b2dc24fe4 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Fri, 8 Dec 2017 23:29:09 +0800 Subject: pinctrl: meson-axg: adjust spicc pin naming According to datasheet, we should use numbers for the pin naming instead of letters. The patch here try to fix this to keep the consistency. This patch should not bring any functional change. Fixes: 83c566806a68 ("pinctrl: meson-axg: Add new pinctrl driver for Meson AXG SoC") Suggested-by: Kevin Hilman Signed-off-by: Yixun Lan Acked-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/pinctrl-meson-axg.c | 86 +++++++++++++++---------------- 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c index a1a7d42afd42..1fda9d6c7ea3 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c @@ -156,25 +156,25 @@ static const unsigned int sdio_d3_pins[] = {GPIOX_3}; static const unsigned int sdio_clk_pins[] = {GPIOX_4}; static const unsigned int sdio_cmd_pins[] = {GPIOX_5}; -/* spi_a */ -static const unsigned int spi_clk_a_pins[] = {GPIOZ_0}; -static const unsigned int spi_mosi_a_pins[] = {GPIOZ_1}; -static const unsigned int spi_miso_a_pins[] = {GPIOZ_2}; -static const unsigned int spi_ss0_a_pins[] = {GPIOZ_3}; -static const unsigned int spi_ss1_a_pins[] = {GPIOZ_4}; -static const unsigned int spi_ss2_a_pins[] = {GPIOZ_5}; - -/* spi_b */ -static const unsigned int spi_clk_b_x_pins[] = {GPIOX_19}; -static const unsigned int spi_mosi_b_x_pins[] = {GPIOX_17}; -static const unsigned int spi_miso_b_x_pins[] = {GPIOX_18}; -static const unsigned int spi_ss0_b_x_pins[] = {GPIOX_16}; - -static const unsigned int spi_clk_b_a_pins[] = {GPIOA_4}; -static const unsigned int spi_mosi_b_a_pins[] = {GPIOA_2}; -static const unsigned int spi_miso_b_a_pins[] = {GPIOA_3}; -static const unsigned int spi_ss0_b_a_pins[] = {GPIOA_5}; -static const unsigned int spi_ss1_b_pins[] = {GPIOA_6}; +/* spi0 */ +static const unsigned int spi0_clk_pins[] = {GPIOZ_0}; +static const unsigned int spi0_mosi_pins[] = {GPIOZ_1}; +static const unsigned int spi0_miso_pins[] = {GPIOZ_2}; +static const unsigned int spi0_ss0_pins[] = {GPIOZ_3}; +static const unsigned int spi0_ss1_pins[] = {GPIOZ_4}; +static const unsigned int spi0_ss2_pins[] = {GPIOZ_5}; + +/* spi1 */ +static const unsigned int spi1_clk_x_pins[] = {GPIOX_19}; +static const unsigned int spi1_mosi_x_pins[] = {GPIOX_17}; +static const unsigned int spi1_miso_x_pins[] = {GPIOX_18}; +static const unsigned int spi1_ss0_x_pins[] = {GPIOX_16}; + +static const unsigned int spi1_clk_a_pins[] = {GPIOA_4}; +static const unsigned int spi1_mosi_a_pins[] = {GPIOA_2}; +static const unsigned int spi1_miso_a_pins[] = {GPIOA_3}; +static const unsigned int spi1_ss0_a_pins[] = {GPIOA_5}; +static const unsigned int spi1_ss1_pins[] = {GPIOA_6}; /* i2c0 */ static const unsigned int i2c0_sck_pins[] = {GPIOZ_6}; @@ -429,12 +429,12 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = { GROUP(nor_cs, 3), /* bank GPIOZ */ - GROUP(spi_clk_a, 1), - GROUP(spi_mosi_a, 1), - GROUP(spi_miso_a, 1), - GROUP(spi_ss0_a, 1), - GROUP(spi_ss1_a, 1), - GROUP(spi_ss2_a, 1), + GROUP(spi0_clk, 1), + GROUP(spi0_mosi, 1), + GROUP(spi0_miso, 1), + GROUP(spi0_ss0, 1), + GROUP(spi0_ss1, 1), + GROUP(spi0_ss2, 1), GROUP(i2c0_sck, 1), GROUP(i2c0_sda, 1), GROUP(i2c1_sck_z, 1), @@ -475,10 +475,10 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = { GROUP(jtag_tdi_x, 2), GROUP(jtag_clk_x, 2), GROUP(jtag_tms_x, 2), - GROUP(spi_clk_b_x, 4), - GROUP(spi_mosi_b_x, 4), - GROUP(spi_miso_b_x, 4), - GROUP(spi_ss0_b_x, 4), + GROUP(spi1_clk_x, 4), + GROUP(spi1_mosi_x, 4), + GROUP(spi1_miso_x, 4), + GROUP(spi1_ss0_x, 4), GROUP(pwm_a_x18, 3), GROUP(pwm_a_x20, 1), GROUP(pwm_b_x, 3), @@ -521,11 +521,11 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = { GROUP(spdif_in_a7, 3), GROUP(spdif_in_a19, 1), GROUP(spdif_in_a20, 2), - GROUP(spi_clk_b_a, 3), - GROUP(spi_mosi_b_a, 3), - GROUP(spi_miso_b_a, 3), - GROUP(spi_ss0_b_a, 3), - GROUP(spi_ss1_b, 3), + GROUP(spi1_clk_a, 3), + GROUP(spi1_mosi_a, 3), + GROUP(spi1_miso_a, 3), + GROUP(spi1_ss0_a, 3), + GROUP(spi1_ss1, 3), GROUP(pwm_a_a, 3), GROUP(pwm_b_a, 3), GROUP(pwm_c_a, 3), @@ -696,15 +696,15 @@ static const char * const sdio_groups[] = { "sdio_cmd", "sdio_clk", }; -static const char * const spi_a_groups[] = { - "spi_clk_a", "spi_mosi_a", "spi_miso_a", "spi_ss0_a", - "spi_ss1_a", "spi_ss2_a" +static const char * const spi0_groups[] = { + "spi0_clk", "spi0_mosi", "spi0_miso", "spi0_ss0", + "spi0_ss1", "spi0_ss2" }; -static const char * const spi_b_groups[] = { - "spi_clk_b_x", "spi_mosi_b_x", "spi_miso_b_x", "spi_ss0_b_x", - "spi_clk_b_a", "spi_mosi_b_a", "spi_miso_b_a", "spi_ss0_b_a", - "spi_ss1_b" +static const char * const spi1_groups[] = { + "spi1_clk_x", "spi1_mosi_x", "spi1_miso_x", "spi1_ss0_x", + "spi1_clk_a", "spi1_mosi_a", "spi1_miso_a", "spi1_ss0_a", + "spi1_ss1" }; static const char * const uart_a_groups[] = { @@ -849,8 +849,8 @@ static struct meson_pmx_func meson_axg_periphs_functions[] = { FUNCTION(gpio_periphs), FUNCTION(emmc), FUNCTION(nor), - FUNCTION(spi_a), - FUNCTION(spi_b), + FUNCTION(spi0), + FUNCTION(spi1), FUNCTION(sdio), FUNCTION(nand), FUNCTION(uart_a), -- cgit From 6f2a71a31afd738af446c802e1ed40365afa55b8 Mon Sep 17 00:00:00 2001 From: Stephen Barber Date: Fri, 10 Nov 2017 22:55:53 +0100 Subject: rtc: cros-ec: add cros-ec-rtc driver. On platforms with a Chrome OS EC, the EC can function as a simple RTC. Add a basic driver with this functionality. Signed-off-by: Stephen Barber Signed-off-by: Enric Balletbo i Serra Acked-by: Alexandre Belloni Acked-by: Benson Leung Reviewed-by: Brian Norris Tested-by: Brian Norris Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-cros-ec.c | 413 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 424 insertions(+) create mode 100644 drivers/rtc/rtc-cros-ec.c (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b59a31b079a5..64f4b164932a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1255,6 +1255,16 @@ config RTC_DRV_ZYNQMP If you say yes here you get support for the RTC controller found on Xilinx Zynq Ultrascale+ MPSoC. +config RTC_DRV_CROS_EC + tristate "Chrome OS EC RTC driver" + depends on MFD_CROS_EC + help + If you say yes here you will get support for the + Chrome OS Embedded Controller's RTC. + + This driver can also be built as a module. If so, the module + will be called rtc-cros-ec. + comment "on-CPU RTC drivers" config RTC_DRV_ASM9260 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index f2f50c11dc38..cf9d29e34dbd 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o +obj-$(CONFIG_RTC_DRV_CROS_EC) += rtc-cros-ec.o obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c new file mode 100644 index 000000000000..f0ea6899c731 --- /dev/null +++ b/drivers/rtc/rtc-cros-ec.c @@ -0,0 +1,413 @@ +/* + * RTC driver for Chrome OS Embedded Controller + * + * Copyright (c) 2017, Google, Inc + * + * Author: Stephen Barber + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "cros-ec-rtc" + +/** + * struct cros_ec_rtc - Driver data for EC RTC + * + * @cros_ec: Pointer to EC device + * @rtc: Pointer to RTC device + * @notifier: Notifier info for responding to EC events + * @saved_alarm: Alarm to restore when interrupts are reenabled + */ +struct cros_ec_rtc { + struct cros_ec_device *cros_ec; + struct rtc_device *rtc; + struct notifier_block notifier; + u32 saved_alarm; +}; + +static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command, + u32 *response) +{ + int ret; + struct { + struct cros_ec_command msg; + struct ec_response_rtc data; + } __packed msg; + + memset(&msg, 0, sizeof(msg)); + msg.msg.command = command; + msg.msg.insize = sizeof(msg.data); + + ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + if (ret < 0) { + dev_err(cros_ec->dev, + "error getting %s from EC: %d\n", + command == EC_CMD_RTC_GET_VALUE ? "time" : "alarm", + ret); + return ret; + } + + *response = msg.data.time; + + return 0; +} + +static int cros_ec_rtc_set(struct cros_ec_device *cros_ec, u32 command, + u32 param) +{ + int ret = 0; + struct { + struct cros_ec_command msg; + struct ec_response_rtc data; + } __packed msg; + + memset(&msg, 0, sizeof(msg)); + msg.msg.command = command; + msg.msg.outsize = sizeof(msg.data); + msg.data.time = param; + + ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + if (ret < 0) { + dev_err(cros_ec->dev, "error setting %s on EC: %d\n", + command == EC_CMD_RTC_SET_VALUE ? "time" : "alarm", + ret); + return ret; + } + + return 0; +} + +/* Read the current time from the EC. */ +static int cros_ec_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); + struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; + int ret; + u32 time; + + ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, &time); + if (ret) { + dev_err(dev, "error getting time: %d\n", ret); + return ret; + } + + rtc_time64_to_tm(time, tm); + + return 0; +} + +/* Set the current EC time. */ +static int cros_ec_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); + struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; + int ret; + time64_t time; + + time = rtc_tm_to_time64(tm); + if (time < 0 || time > U32_MAX) + return -EINVAL; + + ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_VALUE, (u32)time); + if (ret < 0) { + dev_err(dev, "error setting time: %d\n", ret); + return ret; + } + + return 0; +} + +/* Read alarm time from RTC. */ +static int cros_ec_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); + struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; + int ret; + u32 current_time, alarm_offset; + + /* + * The EC host command for getting the alarm is relative (i.e. 5 + * seconds from now) whereas rtc_wkalrm is absolute. Get the current + * RTC time first so we can calculate the relative time. + */ + ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); + if (ret < 0) { + dev_err(dev, "error getting time: %d\n", ret); + return ret; + } + + ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_ALARM, &alarm_offset); + if (ret < 0) { + dev_err(dev, "error getting alarm: %d\n", ret); + return ret; + } + + rtc_time64_to_tm(current_time + alarm_offset, &alrm->time); + + return 0; +} + +/* Set the EC's RTC alarm. */ +static int cros_ec_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); + struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; + int ret; + time64_t alarm_time; + u32 current_time, alarm_offset; + + /* + * The EC host command for setting the alarm is relative + * (i.e. 5 seconds from now) whereas rtc_wkalrm is absolute. + * Get the current RTC time first so we can calculate the + * relative time. + */ + ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); + if (ret < 0) { + dev_err(dev, "error getting time: %d\n", ret); + return ret; + } + + alarm_time = rtc_tm_to_time64(&alrm->time); + + if (alarm_time < 0 || alarm_time > U32_MAX) + return -EINVAL; + + if (!alrm->enabled) { + /* + * If the alarm is being disabled, send an alarm + * clear command. + */ + alarm_offset = EC_RTC_ALARM_CLEAR; + cros_ec_rtc->saved_alarm = (u32)alarm_time; + } else { + /* Don't set an alarm in the past. */ + if ((u32)alarm_time < current_time) + alarm_offset = EC_RTC_ALARM_CLEAR; + else + alarm_offset = (u32)alarm_time - current_time; + } + + ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset); + if (ret < 0) { + dev_err(dev, "error setting alarm: %d\n", ret); + return ret; + } + + return 0; +} + +static int cros_ec_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); + struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; + int ret; + u32 current_time, alarm_offset, alarm_value; + + ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); + if (ret < 0) { + dev_err(dev, "error getting time: %d\n", ret); + return ret; + } + + if (enabled) { + /* Restore saved alarm if it's still in the future. */ + if (cros_ec_rtc->saved_alarm < current_time) + alarm_offset = EC_RTC_ALARM_CLEAR; + else + alarm_offset = cros_ec_rtc->saved_alarm - current_time; + + ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, + alarm_offset); + if (ret < 0) { + dev_err(dev, "error restoring alarm: %d\n", ret); + return ret; + } + } else { + /* Disable alarm, saving the old alarm value. */ + ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_ALARM, + &alarm_offset); + if (ret < 0) { + dev_err(dev, "error saving alarm: %d\n", ret); + return ret; + } + + alarm_value = current_time + alarm_offset; + + /* + * If the current EC alarm is already past, we don't want + * to set an alarm when we go through the alarm irq enable + * path. + */ + if (alarm_value < current_time) + cros_ec_rtc->saved_alarm = EC_RTC_ALARM_CLEAR; + else + cros_ec_rtc->saved_alarm = alarm_value; + + alarm_offset = EC_RTC_ALARM_CLEAR; + ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, + alarm_offset); + if (ret < 0) { + dev_err(dev, "error disabling alarm: %d\n", ret); + return ret; + } + } + + return 0; +} + +static int cros_ec_rtc_event(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *_notify) +{ + struct cros_ec_rtc *cros_ec_rtc; + struct rtc_device *rtc; + struct cros_ec_device *cros_ec; + u32 host_event; + + cros_ec_rtc = container_of(nb, struct cros_ec_rtc, notifier); + rtc = cros_ec_rtc->rtc; + cros_ec = cros_ec_rtc->cros_ec; + + host_event = cros_ec_get_host_event(cros_ec); + if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC)) { + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); + return NOTIFY_OK; + } else { + return NOTIFY_DONE; + } +} + +static const struct rtc_class_ops cros_ec_rtc_ops = { + .read_time = cros_ec_rtc_read_time, + .set_time = cros_ec_rtc_set_time, + .read_alarm = cros_ec_rtc_read_alarm, + .set_alarm = cros_ec_rtc_set_alarm, + .alarm_irq_enable = cros_ec_rtc_alarm_irq_enable, +}; + +#ifdef CONFIG_PM_SLEEP +static int cros_ec_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(&pdev->dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(cros_ec_rtc->cros_ec->irq); + + return 0; +} + +static int cros_ec_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(&pdev->dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(cros_ec_rtc->cros_ec->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(cros_ec_rtc_pm_ops, cros_ec_rtc_suspend, + cros_ec_rtc_resume); + +static int cros_ec_rtc_probe(struct platform_device *pdev) +{ + struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); + struct cros_ec_device *cros_ec = ec_dev->ec_dev; + struct cros_ec_rtc *cros_ec_rtc; + struct rtc_time tm; + int ret; + + cros_ec_rtc = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_rtc), + GFP_KERNEL); + if (!cros_ec_rtc) + return -ENOMEM; + + platform_set_drvdata(pdev, cros_ec_rtc); + cros_ec_rtc->cros_ec = cros_ec; + + /* Get initial time */ + ret = cros_ec_rtc_read_time(&pdev->dev, &tm); + if (ret) { + dev_err(&pdev->dev, "failed to read RTC time\n"); + return ret; + } + + ret = device_init_wakeup(&pdev->dev, 1); + if (ret) { + dev_err(&pdev->dev, "failed to initialize wakeup\n"); + return ret; + } + + cros_ec_rtc->rtc = devm_rtc_device_register(&pdev->dev, DRV_NAME, + &cros_ec_rtc_ops, + THIS_MODULE); + if (IS_ERR(cros_ec_rtc->rtc)) { + ret = PTR_ERR(cros_ec_rtc->rtc); + dev_err(&pdev->dev, "failed to register rtc device\n"); + return ret; + } + + /* Get RTC events from the EC. */ + cros_ec_rtc->notifier.notifier_call = cros_ec_rtc_event; + ret = blocking_notifier_chain_register(&cros_ec->event_notifier, + &cros_ec_rtc->notifier); + if (ret) { + dev_err(&pdev->dev, "failed to register notifier\n"); + return ret; + } + + return 0; +} + +static int cros_ec_rtc_remove(struct platform_device *pdev) +{ + struct cros_ec_rtc *cros_ec_rtc = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int ret; + + ret = blocking_notifier_chain_unregister( + &cros_ec_rtc->cros_ec->event_notifier, + &cros_ec_rtc->notifier); + if (ret) { + dev_err(dev, "failed to unregister notifier\n"); + return ret; + } + + return 0; +} + +static struct platform_driver cros_ec_rtc_driver = { + .probe = cros_ec_rtc_probe, + .remove = cros_ec_rtc_remove, + .driver = { + .name = DRV_NAME, + .pm = &cros_ec_rtc_pm_ops, + }, +}; + +module_platform_driver(cros_ec_rtc_driver); + +MODULE_DESCRIPTION("RTC driver for Chrome OS ECs"); +MODULE_AUTHOR("Stephen Barber "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit From e9982024619c7f8f8cce97b0038a0075b135089c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 22 Nov 2017 17:16:18 +0000 Subject: rtc: sun6i: ensure rtc is kfree'd on error The error return path on clk_data allocation failure does not kfree the allocated rtc object. Fix this with a kfree of rtc on the error exit path. Detected by CoverityScan, CID#1452264 ("Resource Leak") Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 3d2216ccd860..5bc28eed1adf 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -201,8 +201,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) clk_data = kzalloc(sizeof(*clk_data) + (sizeof(*clk_data->hws) * 2), GFP_KERNEL); - if (!clk_data) + if (!clk_data) { + kfree(rtc); return; + } spin_lock_init(&rtc->lock); -- cgit From 994ec64c0a193940be7a6fd074668b9446d3b6c3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 4 Dec 2017 14:58:33 +0100 Subject: rtc: ac100: Fix multiple race conditions The probe function is not allowed to fail after registering the RTC because the following may happen: CPU0: CPU1: sys_load_module() do_init_module() do_one_initcall() cmos_do_probe() rtc_device_register() __register_chrdev() cdev->owner = struct module* open("/dev/rtc0") rtc_device_unregister() module_put() free_module() module_free(mod->module_core) /* struct module *module is now freed */ chrdev_open() spin_lock(cdev_lock) cdev_get() try_module_get() module_is_live() /* dereferences already freed struct module* */ Also, the interrupt handler: ac100_rtc_irq() is dereferencing chip->rtc but this may still be NULL when it is called, resulting in: Unable to handle kernel NULL pointer dereference at virtual address 00000194 pgd = (ptrval) [00000194] *pgd=00000000 Internal error: Oops: 5 [#1] SMP ARM Modules linked in: CPU: 0 PID: 72 Comm: irq/71-ac100-rt Not tainted 4.15.0-rc1-next-20171201-dirty #120 Hardware name: Allwinner sun8i Family task: (ptrval) task.stack: (ptrval) PC is at mutex_lock+0x14/0x3c LR is at ac100_rtc_irq+0x38/0xc8 pc : [] lr : [] psr: 60000053 sp : ee9c9f28 ip : 00000000 fp : ee9adfdc r10: 00000000 r9 : c0a04c48 r8 : c015ed18 r7 : ee9bd600 r6 : ee9c9f28 r5 : ee9af590 r4 : c0a04c48 r3 : ef3cb3c0 r2 : 00000000 r1 : ee9af590 r0 : 00000194 Flags: nZCv IRQs on FIQs off Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 4000406a DAC: 00000051 Process irq/71-ac100-rt (pid: 72, stack limit = 0x(ptrval)) Stack: (0xee9c9f28 to 0xee9ca000) 9f20: 00000000 7c2fd1be c015ed18 ee9adf40 ee9c0400 ee9c0400 9f40: ee9adf40 c015ed34 ee9c8000 ee9adf64 ee9c0400 c015f040 ee9adf80 00000000 9f60: c015ee24 7c2fd1be ee9adfc0 ee9adf80 00000000 ee9c8000 ee9adf40 c015eef4 9f80: ef1eba34 c0138f14 ee9c8000 ee9adf80 c0138df4 00000000 00000000 00000000 9fa0: 00000000 00000000 00000000 c01010e8 00000000 00000000 00000000 00000000 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000 ffffffff ffffffff [] (mutex_lock) from [] (ac100_rtc_irq+0x38/0xc8) [] (ac100_rtc_irq) from [] (irq_thread_fn+0x1c/0x54) [] (irq_thread_fn) from [] (irq_thread+0x14c/0x214) [] (irq_thread) from [] (kthread+0x120/0x150) [] (kthread) from [] (ret_from_fork+0x14/0x2c) Solve both issues by moving to devm_rtc_allocate_device()/rtc_register_device() Reported-by: Quentin Schulz Tested-by: Quentin Schulz Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ac100.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 9e336184491c..0e358d4b6738 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -567,6 +567,12 @@ static int ac100_rtc_probe(struct platform_device *pdev) return chip->irq; } + chip->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(chip->rtc)) + return PTR_ERR(chip->rtc); + + chip->rtc->ops = &ac100_rtc_ops; + ret = devm_request_threaded_irq(&pdev->dev, chip->irq, NULL, ac100_rtc_irq, IRQF_SHARED | IRQF_ONESHOT, @@ -586,17 +592,16 @@ static int ac100_rtc_probe(struct platform_device *pdev) /* clear counter alarm pending interrupts */ regmap_write(chip->regmap, AC100_ALM_INT_STA, AC100_ALM_INT_ENABLE); - chip->rtc = devm_rtc_device_register(&pdev->dev, "rtc-ac100", - &ac100_rtc_ops, THIS_MODULE); - if (IS_ERR(chip->rtc)) { - dev_err(&pdev->dev, "unable to register device\n"); - return PTR_ERR(chip->rtc); - } - ret = ac100_rtc_register_clks(chip); if (ret) return ret; + ret = rtc_register_device(chip->rtc); + if (ret) { + dev_err(&pdev->dev, "unable to register device\n"); + return ret; + } + dev_info(&pdev->dev, "RTC enabled\n"); return 0; -- cgit From 2da6877f0e2ced7825a31556ada6b2ac2e50877f Mon Sep 17 00:00:00 2001 From: Andreas Platschek Date: Wed, 6 Dec 2017 20:42:38 +0100 Subject: rtc: omap: fix unbalanced clk_prepare_enable/clk_disable_unprepare There are 2 error paths after clk_prepare_enable() was called, where clk_disable_unprepare() is missing. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Andreas Platschek Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 1d666ac9ef70..09ef802d6e54 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -753,8 +753,10 @@ static int omap_rtc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rtc->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(rtc->base)) + if (IS_ERR(rtc->base)) { + clk_disable_unprepare(rtc->clk); return PTR_ERR(rtc->base); + } platform_set_drvdata(pdev, rtc); @@ -887,6 +889,7 @@ static int omap_rtc_probe(struct platform_device *pdev) return 0; err: + clk_disable_unprepare(rtc->clk); device_init_wakeup(&pdev->dev, false); rtc->type->lock(rtc); pm_runtime_put_sync(&pdev->dev); -- cgit From 20796a2caf011b9a94763e26b89be7a13a2756f5 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Thu, 14 Dec 2017 10:57:03 +0000 Subject: pinctrl: sh-pfc: r8a7794: Add PWM[0123456] support This patch adds PFC PWM[0123456] pin groups and functions, enabling PWM on the r8a7794 and r8a7745. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7794.c | 165 +++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index c557bc8da10d..dccc20ae1130 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -2546,6 +2546,109 @@ static const unsigned int msiof2_tx_b_pins[] = { static const unsigned int msiof2_tx_b_mux[] = { MSIOF2_TXD_B_MARK, }; +/* - PWM -------------------------------------------------------------------- */ +static const unsigned int pwm0_pins[] = { + RCAR_GP_PIN(1, 14), +}; +static const unsigned int pwm0_mux[] = { + PWM0_MARK, +}; +static const unsigned int pwm0_b_pins[] = { + RCAR_GP_PIN(5, 3), +}; +static const unsigned int pwm0_b_mux[] = { + PWM0_B_MARK, +}; +static const unsigned int pwm1_pins[] = { + RCAR_GP_PIN(4, 5), +}; +static const unsigned int pwm1_mux[] = { + PWM1_MARK, +}; +static const unsigned int pwm1_b_pins[] = { + RCAR_GP_PIN(5, 10), +}; +static const unsigned int pwm1_b_mux[] = { + PWM1_B_MARK, +}; +static const unsigned int pwm1_c_pins[] = { + RCAR_GP_PIN(1, 18), +}; +static const unsigned int pwm1_c_mux[] = { + PWM1_C_MARK, +}; +static const unsigned int pwm2_pins[] = { + RCAR_GP_PIN(4, 10), +}; +static const unsigned int pwm2_mux[] = { + PWM2_MARK, +}; +static const unsigned int pwm2_b_pins[] = { + RCAR_GP_PIN(5, 17), +}; +static const unsigned int pwm2_b_mux[] = { + PWM2_B_MARK, +}; +static const unsigned int pwm2_c_pins[] = { + RCAR_GP_PIN(0, 13), +}; +static const unsigned int pwm2_c_mux[] = { + PWM2_C_MARK, +}; +static const unsigned int pwm3_pins[] = { + RCAR_GP_PIN(4, 13), +}; +static const unsigned int pwm3_mux[] = { + PWM3_MARK, +}; +static const unsigned int pwm3_b_pins[] = { + RCAR_GP_PIN(0, 16), +}; +static const unsigned int pwm3_b_mux[] = { + PWM3_B_MARK, +}; +static const unsigned int pwm4_pins[] = { + RCAR_GP_PIN(1, 3), +}; +static const unsigned int pwm4_mux[] = { + PWM4_MARK, +}; +static const unsigned int pwm4_b_pins[] = { + RCAR_GP_PIN(0, 21), +}; +static const unsigned int pwm4_b_mux[] = { + PWM4_B_MARK, +}; +static const unsigned int pwm5_pins[] = { + RCAR_GP_PIN(3, 30), +}; +static const unsigned int pwm5_mux[] = { + PWM5_MARK, +}; +static const unsigned int pwm5_b_pins[] = { + RCAR_GP_PIN(4, 0), +}; +static const unsigned int pwm5_b_mux[] = { + PWM5_B_MARK, +}; +static const unsigned int pwm5_c_pins[] = { + RCAR_GP_PIN(0, 10), +}; +static const unsigned int pwm5_c_mux[] = { + PWM5_C_MARK, +}; +static const unsigned int pwm6_pins[] = { + RCAR_GP_PIN(4, 8), +}; +static const unsigned int pwm6_mux[] = { + PWM6_MARK, +}; +static const unsigned int pwm6_b_pins[] = { + RCAR_GP_PIN(0, 7), +}; +static const unsigned int pwm6_b_mux[] = { + PWM6_B_MARK, +}; /* - QSPI ------------------------------------------------------------------- */ static const unsigned int qspi_ctrl_pins[] = { /* SPCLK, SSL */ @@ -3689,6 +3792,23 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(msiof2_ss2_b), SH_PFC_PIN_GROUP(msiof2_rx_b), SH_PFC_PIN_GROUP(msiof2_tx_b), + SH_PFC_PIN_GROUP(pwm0), + SH_PFC_PIN_GROUP(pwm0_b), + SH_PFC_PIN_GROUP(pwm1), + SH_PFC_PIN_GROUP(pwm1_b), + SH_PFC_PIN_GROUP(pwm1_c), + SH_PFC_PIN_GROUP(pwm2), + SH_PFC_PIN_GROUP(pwm2_b), + SH_PFC_PIN_GROUP(pwm2_c), + SH_PFC_PIN_GROUP(pwm3), + SH_PFC_PIN_GROUP(pwm3_b), + SH_PFC_PIN_GROUP(pwm4), + SH_PFC_PIN_GROUP(pwm4_b), + SH_PFC_PIN_GROUP(pwm5), + SH_PFC_PIN_GROUP(pwm5_b), + SH_PFC_PIN_GROUP(pwm5_c), + SH_PFC_PIN_GROUP(pwm6), + SH_PFC_PIN_GROUP(pwm6_b), SH_PFC_PIN_GROUP(qspi_ctrl), SH_PFC_PIN_GROUP(qspi_data2), SH_PFC_PIN_GROUP(qspi_data4), @@ -4050,6 +4170,44 @@ static const char * const msiof2_groups[] = { "msiof2_tx_b", }; +static const char * const pwm0_groups[] = { + "pwm0", + "pwm0_b", +}; + +static const char * const pwm1_groups[] = { + "pwm1", + "pwm1_b", + "pwm1_c", +}; + +static const char * const pwm2_groups[] = { + "pwm2", + "pwm2_b", + "pwm2_c", +}; + +static const char * const pwm3_groups[] = { + "pwm3", + "pwm3_b", +}; + +static const char * const pwm4_groups[] = { + "pwm4", + "pwm4_b", +}; + +static const char * const pwm5_groups[] = { + "pwm5", + "pwm5_b", + "pwm5_c", +}; + +static const char * const pwm6_groups[] = { + "pwm6", + "pwm6_b", +}; + static const char * const qspi_groups[] = { "qspi_ctrl", "qspi_data2", @@ -4284,6 +4442,13 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(msiof0), SH_PFC_FUNCTION(msiof1), SH_PFC_FUNCTION(msiof2), + SH_PFC_FUNCTION(pwm0), + SH_PFC_FUNCTION(pwm1), + SH_PFC_FUNCTION(pwm2), + SH_PFC_FUNCTION(pwm3), + SH_PFC_FUNCTION(pwm4), + SH_PFC_FUNCTION(pwm5), + SH_PFC_FUNCTION(pwm6), SH_PFC_FUNCTION(qspi), SH_PFC_FUNCTION(scif0), SH_PFC_FUNCTION(scif1), -- cgit From 64dbebc87d5f91435bf4fb8b04a688f570121b7f Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 18 Dec 2017 18:06:50 +0000 Subject: pinctrl: sh-pfc: r8a7794: Add tpu groups and function This patch adds tpu groups and function to r8a7745/r8a7794. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7794.c | 101 +++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index dccc20ae1130..f133b4f323a2 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -3493,6 +3493,79 @@ static const unsigned int ssi9_ctrl_b_pins[] = { static const unsigned int ssi9_ctrl_b_mux[] = { SSI_SCK9_B_MARK, SSI_WS9_B_MARK, }; +/* - TPU -------------------------------------------------------------------- */ +static const unsigned int tpu_to0_pins[] = { + RCAR_GP_PIN(3, 31), +}; +static const unsigned int tpu_to0_mux[] = { + TPUTO0_MARK, +}; +static const unsigned int tpu_to0_b_pins[] = { + RCAR_GP_PIN(3, 30), +}; +static const unsigned int tpu_to0_b_mux[] = { + TPUTO0_B_MARK, +}; +static const unsigned int tpu_to0_c_pins[] = { + RCAR_GP_PIN(1, 18), +}; +static const unsigned int tpu_to0_c_mux[] = { + TPUTO0_C_MARK, +}; +static const unsigned int tpu_to1_pins[] = { + RCAR_GP_PIN(4, 9), +}; +static const unsigned int tpu_to1_mux[] = { + TPUTO1_MARK, +}; +static const unsigned int tpu_to1_b_pins[] = { + RCAR_GP_PIN(4, 0), +}; +static const unsigned int tpu_to1_b_mux[] = { + TPUTO1_B_MARK, +}; +static const unsigned int tpu_to1_c_pins[] = { + RCAR_GP_PIN(4, 4), +}; +static const unsigned int tpu_to1_c_mux[] = { + TPUTO1_C_MARK, +}; +static const unsigned int tpu_to2_pins[] = { + RCAR_GP_PIN(1, 3), +}; +static const unsigned int tpu_to2_mux[] = { + TPUTO2_MARK, +}; +static const unsigned int tpu_to2_b_pins[] = { + RCAR_GP_PIN(1, 0), +}; +static const unsigned int tpu_to2_b_mux[] = { + TPUTO2_B_MARK, +}; +static const unsigned int tpu_to2_c_pins[] = { + RCAR_GP_PIN(0, 22), +}; +static const unsigned int tpu_to2_c_mux[] = { + TPUTO2_C_MARK, +}; +static const unsigned int tpu_to3_pins[] = { + RCAR_GP_PIN(1, 14), +}; +static const unsigned int tpu_to3_mux[] = { + TPUTO3_MARK, +}; +static const unsigned int tpu_to3_b_pins[] = { + RCAR_GP_PIN(1, 13), +}; +static const unsigned int tpu_to3_b_mux[] = { + TPUTO3_B_MARK, +}; +static const unsigned int tpu_to3_c_pins[] = { + RCAR_GP_PIN(0, 21), +}; +static const unsigned int tpu_to3_c_mux[] = { + TPUTO3_C_MARK, +}; /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { RCAR_GP_PIN(5, 24), /* PWEN */ @@ -3926,6 +3999,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(ssi9_ctrl), SH_PFC_PIN_GROUP(ssi9_data_b), SH_PFC_PIN_GROUP(ssi9_ctrl_b), + SH_PFC_PIN_GROUP(tpu_to0), + SH_PFC_PIN_GROUP(tpu_to0_b), + SH_PFC_PIN_GROUP(tpu_to0_c), + SH_PFC_PIN_GROUP(tpu_to1), + SH_PFC_PIN_GROUP(tpu_to1_b), + SH_PFC_PIN_GROUP(tpu_to1_c), + SH_PFC_PIN_GROUP(tpu_to2), + SH_PFC_PIN_GROUP(tpu_to2_b), + SH_PFC_PIN_GROUP(tpu_to2_c), + SH_PFC_PIN_GROUP(tpu_to3), + SH_PFC_PIN_GROUP(tpu_to3_b), + SH_PFC_PIN_GROUP(tpu_to3_c), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), VIN_DATA_PIN_GROUP(vin0_data, 24), @@ -4388,6 +4473,21 @@ static const char * const ssi_groups[] = { "ssi9_ctrl_b", }; +static const char * const tpu_groups[] = { + "tpu_to0", + "tpu_to0_b", + "tpu_to0_c", + "tpu_to1", + "tpu_to1_b", + "tpu_to1_c", + "tpu_to2", + "tpu_to2_b", + "tpu_to2_c", + "tpu_to3", + "tpu_to3_b", + "tpu_to3_c", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -4470,6 +4570,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi1), SH_PFC_FUNCTION(sdhi2), SH_PFC_FUNCTION(ssi), + SH_PFC_FUNCTION(tpu), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(vin0), -- cgit From 0d68d46035a196c91ee70df2ba204ed708bba315 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 18 Dec 2017 18:04:03 +0000 Subject: pinctrl: sh-pfc: r8a7794: Add i2c5 pin groups and function Add i2c5 pin groups and function to r8a7745 PFC driver. Signed-off-by: Biju Das Reviewed-by: Fabrizio Castro Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7794.c | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index f133b4f323a2..164002437594 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -2228,6 +2228,35 @@ static const unsigned int i2c4_e_pins[] = { static const unsigned int i2c4_e_mux[] = { I2C4_SCL_E_MARK, I2C4_SDA_E_MARK, }; +/* - I2C5 ------------------------------------------------------------------- */ +static const unsigned int i2c5_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(4, 14), RCAR_GP_PIN(4, 15), +}; +static const unsigned int i2c5_mux[] = { + I2C5_SCL_MARK, I2C5_SDA_MARK, +}; +static const unsigned int i2c5_b_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15), +}; +static const unsigned int i2c5_b_mux[] = { + I2C5_SCL_B_MARK, I2C5_SDA_B_MARK, +}; +static const unsigned int i2c5_c_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(4, 31), RCAR_GP_PIN(4, 30), +}; +static const unsigned int i2c5_c_mux[] = { + I2C5_SCL_C_MARK, I2C5_SDA_C_MARK, +}; +static const unsigned int i2c5_d_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(3, 13), RCAR_GP_PIN(3, 14), +}; +static const unsigned int i2c5_d_mux[] = { + I2C5_SCL_D_MARK, I2C5_SDA_D_MARK, +}; /* - INTC ------------------------------------------------------------------- */ static const unsigned int intc_irq0_pins[] = { /* IRQ0 */ @@ -3821,6 +3850,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(i2c4_c), SH_PFC_PIN_GROUP(i2c4_d), SH_PFC_PIN_GROUP(i2c4_e), + SH_PFC_PIN_GROUP(i2c5), + SH_PFC_PIN_GROUP(i2c5_b), + SH_PFC_PIN_GROUP(i2c5_c), + SH_PFC_PIN_GROUP(i2c5_d), SH_PFC_PIN_GROUP(intc_irq0), SH_PFC_PIN_GROUP(intc_irq1), SH_PFC_PIN_GROUP(intc_irq2), @@ -4196,6 +4229,13 @@ static const char * const i2c4_groups[] = { "i2c4_e", }; +static const char * const i2c5_groups[] = { + "i2c5", + "i2c5_b", + "i2c5_c", + "i2c5_d", +}; + static const char * const intc_groups[] = { "intc_irq0", "intc_irq1", @@ -4537,6 +4577,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(i2c2), SH_PFC_FUNCTION(i2c3), SH_PFC_FUNCTION(i2c4), + SH_PFC_FUNCTION(i2c5), SH_PFC_FUNCTION(intc), SH_PFC_FUNCTION(mmc), SH_PFC_FUNCTION(msiof0), -- cgit From 21047d5736918b19a3efe11e8ace856cb1b4b403 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 18 Dec 2017 17:52:07 +0000 Subject: pinctrl: sh-pfc: r8a7791: Add tpu groups and function This patch adds tpu groups and function to r8a7743/r8a7791/r8a7793. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 42 ++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index c01ef02d326b..5811784d88cb 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -4145,6 +4145,32 @@ static const unsigned int ssi9_ctrl_b_mux[] = { SSI_SCK9_B_MARK, SSI_WS9_B_MARK, }; +/* - TPU -------------------------------------------------------------------- */ +static const unsigned int tpu_to0_pins[] = { + RCAR_GP_PIN(6, 14), +}; +static const unsigned int tpu_to0_mux[] = { + TPU_TO0_MARK, +}; +static const unsigned int tpu_to1_pins[] = { + RCAR_GP_PIN(1, 17), +}; +static const unsigned int tpu_to1_mux[] = { + TPU_TO1_MARK, +}; +static const unsigned int tpu_to2_pins[] = { + RCAR_GP_PIN(1, 18), +}; +static const unsigned int tpu_to2_mux[] = { + TPU_TO2_MARK, +}; +static const unsigned int tpu_to3_pins[] = { + RCAR_GP_PIN(1, 24), +}; +static const unsigned int tpu_to3_mux[] = { + TPU_TO3_MARK, +}; + /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { RCAR_GP_PIN(7, 23), /* PWEN */ @@ -4431,7 +4457,7 @@ static const unsigned int vin2_clk_mux[] = { }; static const struct { - struct sh_pfc_pin_group common[342]; + struct sh_pfc_pin_group common[346]; struct sh_pfc_pin_group r8a779x[9]; } pinmux_groups = { .common = { @@ -4743,6 +4769,10 @@ static const struct { SH_PFC_PIN_GROUP(ssi9_data_b), SH_PFC_PIN_GROUP(ssi9_ctrl), SH_PFC_PIN_GROUP(ssi9_ctrl_b), + SH_PFC_PIN_GROUP(tpu_to0), + SH_PFC_PIN_GROUP(tpu_to1), + SH_PFC_PIN_GROUP(tpu_to2), + SH_PFC_PIN_GROUP(tpu_to3), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), VIN_DATA_PIN_GROUP(vin0_data, 24), @@ -5278,6 +5308,13 @@ static const char * const ssi_groups[] = { "ssi9_ctrl_b", }; +static const char * const tpu_groups[] = { + "tpu_to0", + "tpu_to1", + "tpu_to2", + "tpu_to3", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -5327,7 +5364,7 @@ static const char * const vin2_groups[] = { }; static const struct { - struct sh_pfc_function common[57]; + struct sh_pfc_function common[58]; struct sh_pfc_function r8a779x[2]; } pinmux_functions = { .common = { @@ -5383,6 +5420,7 @@ static const struct { SH_PFC_FUNCTION(sdhi1), SH_PFC_FUNCTION(sdhi2), SH_PFC_FUNCTION(ssi), + SH_PFC_FUNCTION(tpu), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(vin0), -- cgit From 981ed1bfbc6c4660b2ddaa8392893e20a6255048 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 1 Mar 2017 10:32:57 -0800 Subject: pinctrl: Really force states during suspend/resume In case a platform only defaults a "default" set of pins, but not a "sleep" set of pins, and this particular platform suspends and resumes in a way that the pin states are not preserved by the hardware, when we resume, we would call pinctrl_single_resume() -> pinctrl_force_default() -> pinctrl_select_state() and the first thing we do is check that the pins state is the same as before, and do nothing. In order to fix this, decouple the actual state change from pinctrl_select_state() and move it pinctrl_commit_state(), while keeping the p->state == state check in pinctrl_select_state() not to change the caller assumptions. pinctrl_force_sleep() and pinctrl_force_default() are updated to bypass the state check by calling pinctrl_commit_state(). [Linus Walleij] The forced pin control states are currently only used in some pin controller drivers that grab their own reference to their own pins. This is equal to the pin control hogs: pins taken by pin control devices since there are no corresponding device in the Linux device hierarchy, such as memory controller lines or unused GPIO lines, or GPIO lines that are used orthogonally from the GPIO subsystem but pincontrol-wise managed as hogs (non-strict mode, allowing simultaneous use by GPIO and pin control). For this case forcing the state from the drivers' suspend()/resume() callbacks makes sense and should semantically match the name of the function. Fixes: 6e5e959dde0d ("pinctrl: API changes to support multiple states per device") Signed-off-by: Florian Fainelli Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 4c8d5b23e4d0..2c0dbfcff3e6 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1189,19 +1189,16 @@ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, EXPORT_SYMBOL_GPL(pinctrl_lookup_state); /** - * pinctrl_select_state() - select/activate/program a pinctrl state to HW + * pinctrl_commit_state() - select/activate/program a pinctrl state to HW * @p: the pinctrl handle for the device that requests configuration * @state: the state handle to select/activate/program */ -int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) +static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) { struct pinctrl_setting *setting, *setting2; struct pinctrl_state *old_state = p->state; int ret; - if (p->state == state) - return 0; - if (p->state) { /* * For each pinmux setting in the old state, forget SW's record @@ -1265,6 +1262,19 @@ unapply_new_state: return ret; } + +/** + * pinctrl_select_state() - select/activate/program a pinctrl state to HW + * @p: the pinctrl handle for the device that requests configuration + * @state: the state handle to select/activate/program + */ +int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) +{ + if (p->state == state) + return 0; + + return pinctrl_commit_state(p, state); +} EXPORT_SYMBOL_GPL(pinctrl_select_state); static void devm_pinctrl_release(struct device *dev, void *res) @@ -1430,7 +1440,7 @@ void pinctrl_unregister_map(const struct pinctrl_map *map) int pinctrl_force_sleep(struct pinctrl_dev *pctldev) { if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_sleep)) - return pinctrl_select_state(pctldev->p, pctldev->hog_sleep); + return pinctrl_commit_state(pctldev->p, pctldev->hog_sleep); return 0; } EXPORT_SYMBOL_GPL(pinctrl_force_sleep); @@ -1442,7 +1452,7 @@ EXPORT_SYMBOL_GPL(pinctrl_force_sleep); int pinctrl_force_default(struct pinctrl_dev *pctldev) { if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_default)) - return pinctrl_select_state(pctldev->p, pctldev->hog_default); + return pinctrl_commit_state(pctldev->p, pctldev->hog_default); return 0; } EXPORT_SYMBOL_GPL(pinctrl_force_default); -- cgit From 4ef4cc13eab265eb3ff56b8269e5a5b96b2169e5 Mon Sep 17 00:00:00 2001 From: Ludovic Barre Date: Mon, 18 Dec 2017 16:17:49 +0100 Subject: pinctrl: stm32: Add STM32MP157 MPU support This driver consists of 2 controllers due to a hole in mapping: -1 controller for GPIO bankA to K. -1 controller for GPIO bankZ. Signed-off-by: Alexandre Torgue Signed-off-by: Ludovic Barre Reviewed-by: Rob Herring Signed-off-by: Linus Walleij --- drivers/pinctrl/stm32/Kconfig | 6 + drivers/pinctrl/stm32/Makefile | 1 + drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 2188 ++++++++++++++++++++++++++++ 3 files changed, 2195 insertions(+) create mode 100644 drivers/pinctrl/stm32/pinctrl-stm32mp157.c (limited to 'drivers') diff --git a/drivers/pinctrl/stm32/Kconfig b/drivers/pinctrl/stm32/Kconfig index 7e1fe39a56a5..a6d045d5f156 100644 --- a/drivers/pinctrl/stm32/Kconfig +++ b/drivers/pinctrl/stm32/Kconfig @@ -32,4 +32,10 @@ config PINCTRL_STM32H743 depends on OF default MACH_STM32H743 select PINCTRL_STM32 + +config PINCTRL_STM32MP157 + bool "STMicroelectronics STM32MP157 pin control" if COMPILE_TEST && !MACH_STM32MP157 + depends on OF + default MACH_STM32MP157 + select PINCTRL_STM32 endif diff --git a/drivers/pinctrl/stm32/Makefile b/drivers/pinctrl/stm32/Makefile index d13ca3573486..b52223d6810c 100644 --- a/drivers/pinctrl/stm32/Makefile +++ b/drivers/pinctrl/stm32/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_PINCTRL_STM32F429) += pinctrl-stm32f429.o obj-$(CONFIG_PINCTRL_STM32F469) += pinctrl-stm32f469.o obj-$(CONFIG_PINCTRL_STM32F746) += pinctrl-stm32f746.o obj-$(CONFIG_PINCTRL_STM32H743) += pinctrl-stm32h743.o +obj-$(CONFIG_PINCTRL_STM32MP157) += pinctrl-stm32mp157.o diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c new file mode 100644 index 000000000000..7c7d6284b23c --- /dev/null +++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c @@ -0,0 +1,2188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ +#include +#include +#include + +#include "pinctrl-stm32.h" + +static const struct stm32_desc_pin stm32mp157_pins[] = { + STM32_PIN( + PINCTRL_PIN(0, "PA0"), + STM32_FUNCTION(0, "GPIOA0"), + STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), + STM32_FUNCTION(3, "TIM5_CH1"), + STM32_FUNCTION(4, "TIM8_ETR"), + STM32_FUNCTION(5, "TIM15_BKIN"), + STM32_FUNCTION(8, "USART2_CTS_NSS USART_BOOT2_CTS_NSS"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "SDMMC2_CMD"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(12, "ETH_GMII_CRS ETH_MII_CRS"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(1, "PA1"), + STM32_FUNCTION(0, "GPIOA1"), + STM32_FUNCTION(1, "ETH_CLK"), + STM32_FUNCTION(2, "TIM2_CH2"), + STM32_FUNCTION(3, "TIM5_CH2"), + STM32_FUNCTION(4, "LPTIM3_OUT"), + STM32_FUNCTION(5, "TIM15_CH1N"), + STM32_FUNCTION(8, "USART2_RTS USART_BOOT2_RTS"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO3 QUADSPI_BOOTBK1_IO3"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(12, "ETH_GMII_RX_CLK ETH_MII_RX_CLK ETH_RGMII_RX_CLK ETH_RMII_REF_CLK"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(2, "PA2"), + STM32_FUNCTION(0, "GPIOA2"), + STM32_FUNCTION(2, "TIM2_CH3"), + STM32_FUNCTION(3, "TIM5_CH3"), + STM32_FUNCTION(4, "LPTIM4_OUT"), + STM32_FUNCTION(5, "TIM15_CH1"), + STM32_FUNCTION(8, "USART2_TX USART_BOOT2_TX"), + STM32_FUNCTION(9, "SAI2_SCK_B"), + STM32_FUNCTION(11, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), + STM32_FUNCTION(12, "ETH_MDIO"), + STM32_FUNCTION(13, "MDIOS_MDIO"), + STM32_FUNCTION(15, "LCD_R1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(3, "PA3"), + STM32_FUNCTION(0, "GPIOA3"), + STM32_FUNCTION(2, "TIM2_CH4"), + STM32_FUNCTION(3, "TIM5_CH4"), + STM32_FUNCTION(4, "LPTIM5_OUT"), + STM32_FUNCTION(5, "TIM15_CH2"), + STM32_FUNCTION(8, "USART2_RX USART_BOOT2_RX"), + STM32_FUNCTION(10, "LCD_B2"), + STM32_FUNCTION(12, "ETH_GMII_COL ETH_MII_COL"), + STM32_FUNCTION(15, "LCD_B5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(4, "PA4"), + STM32_FUNCTION(0, "GPIOA4"), + STM32_FUNCTION(1, "HDP0"), + STM32_FUNCTION(3, "TIM5_ETR"), + STM32_FUNCTION(5, "SAI4_D2"), + STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), + STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"), + STM32_FUNCTION(8, "USART2_CK USART_BOOT2_CK"), + STM32_FUNCTION(9, "SPI6_NSS"), + STM32_FUNCTION(13, "SAI4_FS_A"), + STM32_FUNCTION(14, "DCMI_HSYNC"), + STM32_FUNCTION(15, "LCD_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(5, "PA5"), + STM32_FUNCTION(0, "GPIOA5"), + STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), + STM32_FUNCTION(4, "TIM8_CH1N"), + STM32_FUNCTION(5, "SAI4_CK1"), + STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"), + STM32_FUNCTION(9, "SPI6_SCK"), + STM32_FUNCTION(13, "SAI4_MCLK_A"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(6, "PA6"), + STM32_FUNCTION(0, "GPIOA6"), + STM32_FUNCTION(2, "TIM1_BKIN"), + STM32_FUNCTION(3, "TIM3_CH1"), + STM32_FUNCTION(4, "TIM8_BKIN"), + STM32_FUNCTION(5, "SAI4_CK2"), + STM32_FUNCTION(6, "SPI1_MISO I2S1_SDI"), + STM32_FUNCTION(9, "SPI6_MISO"), + STM32_FUNCTION(10, "TIM13_CH1"), + STM32_FUNCTION(12, "MDIOS_MDC"), + STM32_FUNCTION(13, "SAI4_SCK_A"), + STM32_FUNCTION(14, "DCMI_PIXCLK"), + STM32_FUNCTION(15, "LCD_G2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(7, "PA7"), + STM32_FUNCTION(0, "GPIOA7"), + STM32_FUNCTION(2, "TIM1_CH1N"), + STM32_FUNCTION(3, "TIM3_CH2"), + STM32_FUNCTION(4, "TIM8_CH1N"), + STM32_FUNCTION(5, "SAI4_D1"), + STM32_FUNCTION(6, "SPI1_MOSI I2S1_SDO"), + STM32_FUNCTION(9, "SPI6_MOSI"), + STM32_FUNCTION(10, "TIM14_CH1"), + STM32_FUNCTION(11, "QUADSPI_CLK"), + STM32_FUNCTION(12, "ETH_GMII_RX_DV ETH_MII_RX_DV ETH_RGMII_RX_CTL ETH_RMII_CRS_DV"), + STM32_FUNCTION(13, "SAI4_SD_A"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(8, "PA8"), + STM32_FUNCTION(0, "GPIOA8"), + STM32_FUNCTION(1, "MCO1"), + STM32_FUNCTION(2, "TIM1_CH1"), + STM32_FUNCTION(4, "TIM8_BKIN2"), + STM32_FUNCTION(5, "I2C3_SCL"), + STM32_FUNCTION(6, "SPI3_MOSI I2S3_SDO"), + STM32_FUNCTION(8, "USART1_CK"), + STM32_FUNCTION(9, "SDMMC2_CKIN SDMMC_BOOT2_CKIN"), + STM32_FUNCTION(10, "SDMMC2_D4 SDMMC_BOOT2_D4"), + STM32_FUNCTION(11, "USBO_SOF"), + STM32_FUNCTION(13, "SAI4_SD_B"), + STM32_FUNCTION(14, "UART7_RX"), + STM32_FUNCTION(15, "LCD_R6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(9, "PA9"), + STM32_FUNCTION(0, "GPIOA9"), + STM32_FUNCTION(2, "TIM1_CH2"), + STM32_FUNCTION(5, "I2C3_SMBA"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(8, "USART1_TX"), + STM32_FUNCTION(9, "SDMMC2_CDIR SDMMC_BOOT2_CDIR"), + STM32_FUNCTION(10, "CAN1_RXFD"), + STM32_FUNCTION(11, "SDMMC2_D5 SDMMC_BOOT2_D5"), + STM32_FUNCTION(14, "DCMI_D0"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(10, "PA10"), + STM32_FUNCTION(0, "GPIOA10"), + STM32_FUNCTION(2, "TIM1_CH3"), + STM32_FUNCTION(6, "SPI3_NSS I2S3_WS"), + STM32_FUNCTION(8, "USART1_RX"), + STM32_FUNCTION(10, "CAN1_TXFD"), + STM32_FUNCTION(12, "MDIOS_MDIO"), + STM32_FUNCTION(13, "SAI4_FS_B"), + STM32_FUNCTION(14, "DCMI_D1"), + STM32_FUNCTION(15, "LCD_B1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(11, "PA11"), + STM32_FUNCTION(0, "GPIOA11"), + STM32_FUNCTION(2, "TIM1_CH4"), + STM32_FUNCTION(3, "I2C6_SCL"), + STM32_FUNCTION(5, "I2C5_SCL"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(7, "UART4_RX"), + STM32_FUNCTION(8, "USART1_CTS_NSS"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(12, "PA12"), + STM32_FUNCTION(0, "GPIOA12"), + STM32_FUNCTION(2, "TIM1_ETR"), + STM32_FUNCTION(3, "I2C6_SDA"), + STM32_FUNCTION(5, "I2C5_SDA"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "UART4_TX"), + STM32_FUNCTION(8, "USART1_RTS"), + STM32_FUNCTION(9, "SAI2_FS_B"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(13, "PA13"), + STM32_FUNCTION(0, "GPIOA13"), + STM32_FUNCTION(1, "DBTRGO"), + STM32_FUNCTION(2, "DBTRGI"), + STM32_FUNCTION(3, "MCO1"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(14, "PA14"), + STM32_FUNCTION(0, "GPIOA14"), + STM32_FUNCTION(1, "DBTRGO"), + STM32_FUNCTION(2, "DBTRGI"), + STM32_FUNCTION(3, "MCO2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(15, "PA15"), + STM32_FUNCTION(0, "GPIOA15"), + STM32_FUNCTION(1, "DBTRGI"), + STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), + STM32_FUNCTION(3, "SAI4_D2"), + STM32_FUNCTION(4, "SDMMC1_CDIR"), + STM32_FUNCTION(5, "HDMI_CEC"), + STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), + STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"), + STM32_FUNCTION(8, "SPI6_NSS"), + STM32_FUNCTION(9, "UART4_RTS UART_BOOT4_RTS"), + STM32_FUNCTION(10, "SDMMC2_D5 SDMMC_BOOT2_D5"), + STM32_FUNCTION(11, "SDMMC2_CDIR SDMMC_BOOT2_CDIR"), + STM32_FUNCTION(12, "SDMMC1_D5 SDMMC_BOOT1_D5"), + STM32_FUNCTION(13, "SAI4_FS_A"), + STM32_FUNCTION(14, "UART7_TX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(16, "PB0"), + STM32_FUNCTION(0, "GPIOB0"), + STM32_FUNCTION(2, "TIM1_CH2N"), + STM32_FUNCTION(3, "TIM3_CH3"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(7, "DFSDM_CKOUT"), + STM32_FUNCTION(9, "UART4_CTS UART_BOOT4_CTS"), + STM32_FUNCTION(10, "LCD_R3"), + STM32_FUNCTION(12, "ETH_GMII_RXD2 ETH_MII_RXD2 ETH_RGMII_RXD2"), + STM32_FUNCTION(13, "MDIOS_MDIO"), + STM32_FUNCTION(15, "LCD_G1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(17, "PB1"), + STM32_FUNCTION(0, "GPIOB1"), + STM32_FUNCTION(2, "TIM1_CH3N"), + STM32_FUNCTION(3, "TIM3_CH4"), + STM32_FUNCTION(4, "TIM8_CH3N"), + STM32_FUNCTION(7, "DFSDM_DATA1"), + STM32_FUNCTION(10, "LCD_R6"), + STM32_FUNCTION(12, "ETH_GMII_RXD3 ETH_MII_RXD3 ETH_RGMII_RXD3"), + STM32_FUNCTION(13, "MDIOS_MDC"), + STM32_FUNCTION(15, "LCD_G0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(18, "PB2"), + STM32_FUNCTION(0, "GPIOB2"), + STM32_FUNCTION(1, "TRACED4"), + STM32_FUNCTION(2, "RTC_OUT2"), + STM32_FUNCTION(3, "SAI1_D1"), + STM32_FUNCTION(4, "DFSDM_CK1"), + STM32_FUNCTION(5, "USART1_RX"), + STM32_FUNCTION(6, "I2S_CKIN"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(8, "SPI3_MOSI I2S3_SDO"), + STM32_FUNCTION(9, "UART4_RX UART_BOOT4_RX"), + STM32_FUNCTION(10, "QUADSPI_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(19, "PB3"), + STM32_FUNCTION(0, "GPIOB3"), + STM32_FUNCTION(1, "TRACED9"), + STM32_FUNCTION(2, "TIM2_CH2"), + STM32_FUNCTION(5, "SAI4_CK1"), + STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"), + STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"), + STM32_FUNCTION(9, "SPI6_SCK"), + STM32_FUNCTION(10, "SDMMC2_D2 SDMMC_BOOT2_D2"), + STM32_FUNCTION(13, "SAI4_MCLK_A"), + STM32_FUNCTION(14, "UART7_RX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(20, "PB4"), + STM32_FUNCTION(0, "GPIOB4"), + STM32_FUNCTION(1, "TRACED8"), + STM32_FUNCTION(2, "TIM16_BKIN"), + STM32_FUNCTION(3, "TIM3_CH1"), + STM32_FUNCTION(5, "SAI4_CK2"), + STM32_FUNCTION(6, "SPI1_MISO I2S1_SDI"), + STM32_FUNCTION(7, "SPI3_MISO I2S3_SDI"), + STM32_FUNCTION(8, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(9, "SPI6_MISO"), + STM32_FUNCTION(10, "SDMMC2_D3 SDMMC_BOOT2_D3"), + STM32_FUNCTION(13, "SAI4_SCK_A"), + STM32_FUNCTION(14, "UART7_TX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(21, "PB5"), + STM32_FUNCTION(0, "GPIOB5"), + STM32_FUNCTION(1, "ETH_CLK"), + STM32_FUNCTION(2, "TIM17_BKIN"), + STM32_FUNCTION(3, "TIM3_CH2"), + STM32_FUNCTION(4, "SAI4_D1"), + STM32_FUNCTION(5, "I2C1_SMBA"), + STM32_FUNCTION(6, "SPI1_MOSI I2S1_SDO"), + STM32_FUNCTION(7, "I2C4_SMBA"), + STM32_FUNCTION(8, "SPI3_MOSI I2S3_SDO"), + STM32_FUNCTION(9, "SPI6_MOSI"), + STM32_FUNCTION(10, "CAN2_RX"), + STM32_FUNCTION(11, "SAI4_SD_A"), + STM32_FUNCTION(12, "ETH_PPS_OUT"), + STM32_FUNCTION(13, "UART5_RX UART_BOOT5_RX"), + STM32_FUNCTION(14, "DCMI_D10"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(22, "PB6"), + STM32_FUNCTION(0, "GPIOB6"), + STM32_FUNCTION(2, "TIM16_CH1N"), + STM32_FUNCTION(3, "TIM4_CH1"), + STM32_FUNCTION(5, "I2C1_SCL"), + STM32_FUNCTION(6, "HDMI_CEC"), + STM32_FUNCTION(7, "I2C4_SCL"), + STM32_FUNCTION(8, "USART1_TX"), + STM32_FUNCTION(10, "CAN2_TX"), + STM32_FUNCTION(11, "QUADSPI_BK1_NCS QUADSPI_BOOTBK1_NCS"), + STM32_FUNCTION(12, "DFSDM_DATA5"), + STM32_FUNCTION(13, "UART5_TX"), + STM32_FUNCTION(14, "DCMI_D5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(23, "PB7"), + STM32_FUNCTION(0, "GPIOB7"), + STM32_FUNCTION(2, "TIM17_CH1N"), + STM32_FUNCTION(3, "TIM4_CH2"), + STM32_FUNCTION(5, "I2C1_SDA"), + STM32_FUNCTION(7, "I2C4_SDA"), + STM32_FUNCTION(8, "USART1_RX"), + STM32_FUNCTION(10, "CAN2_TXFD"), + STM32_FUNCTION(11, "SDMMC2_D1 SDMMC_BOOT2_D1"), + STM32_FUNCTION(12, "DFSDM_CK5"), + STM32_FUNCTION(13, "FMC_NL"), + STM32_FUNCTION(14, "DCMI_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(24, "PB8"), + STM32_FUNCTION(0, "GPIOB8"), + STM32_FUNCTION(1, "HDP6"), + STM32_FUNCTION(2, "TIM16_CH1"), + STM32_FUNCTION(3, "TIM4_CH3"), + STM32_FUNCTION(4, "DFSDM_CK7"), + STM32_FUNCTION(5, "I2C1_SCL"), + STM32_FUNCTION(6, "SDMMC1_CKIN SDMMC_BOOT1_CKIN"), + STM32_FUNCTION(7, "I2C4_SCL"), + STM32_FUNCTION(8, "SDMMC2_CKIN SDMMC_BOOT2_CKIN"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(11, "SDMMC2_D4 SDMMC_BOOT2_D4"), + STM32_FUNCTION(12, "ETH_GMII_TXD3 ETH_MII_TXD3 ETH_RGMII_TXD3"), + STM32_FUNCTION(13, "SDMMC1_D4 SDMMC_BOOT1_D4"), + STM32_FUNCTION(14, "DCMI_D6"), + STM32_FUNCTION(15, "LCD_B6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(25, "PB9"), + STM32_FUNCTION(0, "GPIOB9"), + STM32_FUNCTION(1, "HDP7"), + STM32_FUNCTION(2, "TIM17_CH1"), + STM32_FUNCTION(3, "TIM4_CH4"), + STM32_FUNCTION(4, "DFSDM_DATA7"), + STM32_FUNCTION(5, "I2C1_SDA"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(7, "I2C4_SDA"), + STM32_FUNCTION(8, "SDMMC2_CDIR SDMMC_BOOT2_CDIR"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(11, "SDMMC2_D5 SDMMC_BOOT2_D5"), + STM32_FUNCTION(12, "SDMMC1_CDIR SDMMC_BOOT1_CDIR"), + STM32_FUNCTION(13, "SDMMC1_D5 SDMMC_BOOT1_D5"), + STM32_FUNCTION(14, "DCMI_D7"), + STM32_FUNCTION(15, "LCD_B7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(26, "PB10"), + STM32_FUNCTION(0, "GPIOB10"), + STM32_FUNCTION(2, "TIM2_CH3"), + STM32_FUNCTION(4, "LPTIM2_IN1"), + STM32_FUNCTION(5, "I2C2_SCL"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "DFSDM_DATA7"), + STM32_FUNCTION(8, "USART3_TX USART_BOOT3_TX"), + STM32_FUNCTION(10, "QUADSPI_BK1_NCS"), + STM32_FUNCTION(12, "ETH_GMII_RX_ER ETH_MII_RX_ER"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(27, "PB11"), + STM32_FUNCTION(0, "GPIOB11"), + STM32_FUNCTION(2, "TIM2_CH4"), + STM32_FUNCTION(4, "LPTIM2_ETR"), + STM32_FUNCTION(5, "I2C2_SDA"), + STM32_FUNCTION(7, "DFSDM_CK7"), + STM32_FUNCTION(8, "USART3_RX"), + STM32_FUNCTION(12, "ETH_GMII_TX_EN ETH_MII_TX_EN ETH_RGMII_TX_CTL ETH_RMII_TX_EN"), + STM32_FUNCTION(14, "DSI_TE"), + STM32_FUNCTION(15, "LCD_G5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(28, "PB12"), + STM32_FUNCTION(0, "GPIOB12"), + STM32_FUNCTION(2, "TIM1_BKIN"), + STM32_FUNCTION(3, "I2C6_SMBA"), + STM32_FUNCTION(5, "I2C2_SMBA"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(7, "DFSDM_DATA1"), + STM32_FUNCTION(8, "USART3_CK USART_BOOT3_CK"), + STM32_FUNCTION(9, "USART3_RX USART_BOOT3_RX"), + STM32_FUNCTION(10, "CAN2_RX"), + STM32_FUNCTION(12, "ETH_GMII_TXD0 ETH_MII_TXD0 ETH_RGMII_TXD0 ETH_RMII_TXD0"), + STM32_FUNCTION(15, "UART5_RX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(29, "PB13"), + STM32_FUNCTION(0, "GPIOB13"), + STM32_FUNCTION(2, "TIM1_CH1N"), + STM32_FUNCTION(4, "DFSDM_CKOUT"), + STM32_FUNCTION(5, "LPTIM2_OUT"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "DFSDM_CK1"), + STM32_FUNCTION(8, "USART3_CTS_NSS USART_BOOT3_CTS_NSS"), + STM32_FUNCTION(10, "CAN2_TX"), + STM32_FUNCTION(12, "ETH_GMII_TXD1 ETH_MII_TXD1 ETH_RGMII_TXD1 ETH_RMII_TXD1"), + STM32_FUNCTION(15, "UART5_TX UART_BOOT5_TX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(30, "PB14"), + STM32_FUNCTION(0, "GPIOB14"), + STM32_FUNCTION(2, "TIM1_CH2N"), + STM32_FUNCTION(3, "TIM12_CH1"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(5, "USART1_TX"), + STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"), + STM32_FUNCTION(7, "DFSDM_DATA2"), + STM32_FUNCTION(8, "USART3_RTS USART_BOOT3_RTS"), + STM32_FUNCTION(10, "SDMMC2_D0 SDMMC_BOOT2_D0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(31, "PB15"), + STM32_FUNCTION(0, "GPIOB15"), + STM32_FUNCTION(1, "RTC_REFIN"), + STM32_FUNCTION(2, "TIM1_CH3N"), + STM32_FUNCTION(3, "TIM12_CH2"), + STM32_FUNCTION(4, "TIM8_CH3N"), + STM32_FUNCTION(5, "USART1_RX"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), + STM32_FUNCTION(7, "DFSDM_CK2"), + STM32_FUNCTION(10, "SDMMC2_D1 SDMMC_BOOT2_D1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(32, "PC0"), + STM32_FUNCTION(0, "GPIOC0"), + STM32_FUNCTION(4, "DFSDM_CK0"), + STM32_FUNCTION(5, "LPTIM2_IN2"), + STM32_FUNCTION(7, "DFSDM_DATA4"), + STM32_FUNCTION(9, "SAI2_FS_B"), + STM32_FUNCTION(11, "QUADSPI_BK2_NCS QUADSPI_BOOTBK2_NCS"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(33, "PC1"), + STM32_FUNCTION(0, "GPIOC1"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(3, "SAI1_D1"), + STM32_FUNCTION(4, "DFSDM_DATA0"), + STM32_FUNCTION(5, "DFSDM_CK4"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(10, "SDMMC2_CK"), + STM32_FUNCTION(12, "ETH_MDC"), + STM32_FUNCTION(13, "MDIOS_MDC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(34, "PC2"), + STM32_FUNCTION(0, "GPIOC2"), + STM32_FUNCTION(4, "DFSDM_CK1"), + STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"), + STM32_FUNCTION(7, "DFSDM_CKOUT"), + STM32_FUNCTION(12, "ETH_GMII_TXD2 ETH_MII_TXD2 ETH_RGMII_TXD2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(35, "PC3"), + STM32_FUNCTION(0, "GPIOC3"), + STM32_FUNCTION(1, "TRACECLK"), + STM32_FUNCTION(4, "DFSDM_DATA1"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), + STM32_FUNCTION(12, "ETH_GMII_TX_CLK ETH_MII_TX_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(36, "PC4"), + STM32_FUNCTION(0, "GPIOC4"), + STM32_FUNCTION(4, "DFSDM_CK2"), + STM32_FUNCTION(6, "I2S1_MCK"), + STM32_FUNCTION(10, "SPDIF_IN2"), + STM32_FUNCTION(12, "ETH_GMII_RXD0 ETH_MII_RXD0 ETH_RGMII_RXD0 ETH_RMII_RXD0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(37, "PC5"), + STM32_FUNCTION(0, "GPIOC5"), + STM32_FUNCTION(3, "SAI1_D3"), + STM32_FUNCTION(4, "DFSDM_DATA2"), + STM32_FUNCTION(5, "SAI4_D4"), + STM32_FUNCTION(7, "SAI1_D4"), + STM32_FUNCTION(10, "SPDIF_IN3"), + STM32_FUNCTION(12, "ETH_GMII_RXD1 ETH_MII_RXD1 ETH_RGMII_RXD1 ETH_RMII_RXD1"), + STM32_FUNCTION(13, "SAI4_D3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(38, "PC6"), + STM32_FUNCTION(0, "GPIOC6"), + STM32_FUNCTION(1, "HDP1"), + STM32_FUNCTION(3, "TIM3_CH1"), + STM32_FUNCTION(4, "TIM8_CH1"), + STM32_FUNCTION(5, "DFSDM_CK3"), + STM32_FUNCTION(6, "I2S2_MCK"), + STM32_FUNCTION(8, "USART6_TX USART_BOOT6_TX"), + STM32_FUNCTION(9, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), + STM32_FUNCTION(10, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), + STM32_FUNCTION(11, "SDMMC2_D6 SDMMC_BOOT2_D6"), + STM32_FUNCTION(12, "DSI_TE"), + STM32_FUNCTION(13, "SDMMC1_D6 SDMMC_BOOT1_D6"), + STM32_FUNCTION(14, "DCMI_D0"), + STM32_FUNCTION(15, "LCD_HSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(39, "PC7"), + STM32_FUNCTION(0, "GPIOC7"), + STM32_FUNCTION(1, "HDP4"), + STM32_FUNCTION(3, "TIM3_CH2"), + STM32_FUNCTION(4, "TIM8_CH2"), + STM32_FUNCTION(5, "DFSDM_DATA3"), + STM32_FUNCTION(7, "I2S3_MCK"), + STM32_FUNCTION(8, "USART6_RX USART_BOOT6_RX"), + STM32_FUNCTION(9, "SDMMC1_D123DIR SDMMC_BOOT1_D123DIR"), + STM32_FUNCTION(10, "SDMMC2_D123DIR SDMMC_BOOT2_D123DIR"), + STM32_FUNCTION(11, "SDMMC2_D7 SDMMC_BOOT2_D7"), + STM32_FUNCTION(13, "SDMMC1_D7 SDMMC_BOOT1_D7"), + STM32_FUNCTION(14, "DCMI_D1"), + STM32_FUNCTION(15, "LCD_G6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(40, "PC8"), + STM32_FUNCTION(0, "GPIOC8"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(3, "TIM3_CH3"), + STM32_FUNCTION(4, "TIM8_CH3"), + STM32_FUNCTION(7, "UART4_TX"), + STM32_FUNCTION(8, "USART6_CK USART_BOOT6_CK"), + STM32_FUNCTION(9, "UART5_RTS UART_BOOT5_RTS"), + STM32_FUNCTION(13, "SDMMC1_D0 SDMMC_BOOT1_D0"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(41, "PC9"), + STM32_FUNCTION(0, "GPIOC9"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(3, "TIM3_CH4"), + STM32_FUNCTION(4, "TIM8_CH4"), + STM32_FUNCTION(5, "I2C3_SDA"), + STM32_FUNCTION(6, "I2S_CKIN"), + STM32_FUNCTION(9, "UART5_CTS UART_BOOT5_CTS"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO0"), + STM32_FUNCTION(13, "SDMMC1_D1 SDMMC_BOOT1_D1"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(42, "PC10"), + STM32_FUNCTION(0, "GPIOC10"), + STM32_FUNCTION(1, "TRACED2"), + STM32_FUNCTION(4, "DFSDM_CK5"), + STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"), + STM32_FUNCTION(8, "USART3_TX"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO1"), + STM32_FUNCTION(11, "SAI4_MCLK_B"), + STM32_FUNCTION(13, "SDMMC1_D2 SDMMC_BOOT1_D2"), + STM32_FUNCTION(14, "DCMI_D8"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(43, "PC11"), + STM32_FUNCTION(0, "GPIOC11"), + STM32_FUNCTION(1, "TRACED3"), + STM32_FUNCTION(4, "DFSDM_DATA5"), + STM32_FUNCTION(7, "SPI3_MISO I2S3_SDI"), + STM32_FUNCTION(8, "USART3_RX"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "QUADSPI_BK2_NCS QUADSPI_BOOTBK2_NCS"), + STM32_FUNCTION(11, "SAI4_SCK_B"), + STM32_FUNCTION(13, "SDMMC1_D3 SDMMC_BOOT1_D3"), + STM32_FUNCTION(14, "DCMI_D4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(44, "PC12"), + STM32_FUNCTION(0, "GPIOC12"), + STM32_FUNCTION(1, "TRACECLK"), + STM32_FUNCTION(2, "MCO2"), + STM32_FUNCTION(3, "SAI4_D3"), + STM32_FUNCTION(7, "SPI3_MOSI I2S3_SDO"), + STM32_FUNCTION(8, "USART3_CK USART_BOOT3_CK"), + STM32_FUNCTION(9, "UART5_TX"), + STM32_FUNCTION(11, "SAI4_SD_B"), + STM32_FUNCTION(13, "SDMMC1_CK SDMMC_BOOT1_CK"), + STM32_FUNCTION(14, "DCMI_D9"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(45, "PC13"), + STM32_FUNCTION(0, "GPIOC13"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(46, "PC14"), + STM32_FUNCTION(0, "GPIOC14"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(47, "PC15"), + STM32_FUNCTION(0, "GPIOC15"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(48, "PD0"), + STM32_FUNCTION(0, "GPIOD0"), + STM32_FUNCTION(3, "I2C6_SDA"), + STM32_FUNCTION(4, "DFSDM_CK6"), + STM32_FUNCTION(5, "I2C5_SDA"), + STM32_FUNCTION(7, "SAI3_SCK_A"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(11, "SDMMC3_CMD"), + STM32_FUNCTION(12, "DFSDM_DATA7"), + STM32_FUNCTION(13, "FMC_D2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(49, "PD1"), + STM32_FUNCTION(0, "GPIOD1"), + STM32_FUNCTION(3, "I2C6_SCL"), + STM32_FUNCTION(4, "DFSDM_DATA6"), + STM32_FUNCTION(5, "I2C5_SCL"), + STM32_FUNCTION(7, "SAI3_SD_A"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(11, "SDMMC3_D0"), + STM32_FUNCTION(12, "DFSDM_CK7"), + STM32_FUNCTION(13, "FMC_D3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(50, "PD2"), + STM32_FUNCTION(0, "GPIOD2"), + STM32_FUNCTION(3, "TIM3_ETR"), + STM32_FUNCTION(5, "I2C5_SMBA"), + STM32_FUNCTION(7, "UART4_RX"), + STM32_FUNCTION(9, "UART5_RX"), + STM32_FUNCTION(13, "SDMMC1_CMD SDMMC_BOOT1_CMD"), + STM32_FUNCTION(14, "DCMI_D11"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(51, "PD3"), + STM32_FUNCTION(0, "GPIOD3"), + STM32_FUNCTION(1, "HDP5"), + STM32_FUNCTION(4, "DFSDM_CKOUT"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "DFSDM_DATA0"), + STM32_FUNCTION(8, "USART2_CTS_NSS USART_BOOT2_CTS_NSS"), + STM32_FUNCTION(9, "SDMMC1_D123DIR SDMMC_BOOT1_D123DIR"), + STM32_FUNCTION(10, "SDMMC2_D7 SDMMC_BOOT2_D7"), + STM32_FUNCTION(11, "SDMMC2_D123DIR SDMMC_BOOT2_D123DIR"), + STM32_FUNCTION(12, "SDMMC1_D7 SDMMC_BOOT1_D7"), + STM32_FUNCTION(13, "FMC_CLK"), + STM32_FUNCTION(14, "DCMI_D5"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(52, "PD4"), + STM32_FUNCTION(0, "GPIOD4"), + STM32_FUNCTION(7, "SAI3_FS_A"), + STM32_FUNCTION(8, "USART2_RTS USART_BOOT2_RTS"), + STM32_FUNCTION(10, "CAN1_RXFD"), + STM32_FUNCTION(11, "SDMMC3_D1"), + STM32_FUNCTION(12, "DFSDM_CK0"), + STM32_FUNCTION(13, "FMC_NOE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(53, "PD5"), + STM32_FUNCTION(0, "GPIOD5"), + STM32_FUNCTION(8, "USART2_TX"), + STM32_FUNCTION(10, "CAN1_TXFD"), + STM32_FUNCTION(11, "SDMMC3_D2"), + STM32_FUNCTION(13, "FMC_NWE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(54, "PD6"), + STM32_FUNCTION(0, "GPIOD6"), + STM32_FUNCTION(2, "TIM16_CH1N"), + STM32_FUNCTION(3, "SAI1_D1"), + STM32_FUNCTION(4, "DFSDM_CK4"), + STM32_FUNCTION(5, "DFSDM_DATA1"), + STM32_FUNCTION(6, "SPI3_MOSI I2S3_SDO"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(8, "USART2_RX"), + STM32_FUNCTION(10, "CAN2_RXFD"), + STM32_FUNCTION(11, "FMC_INT"), + STM32_FUNCTION(13, "FMC_NWAIT"), + STM32_FUNCTION(14, "DCMI_D10"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(55, "PD7"), + STM32_FUNCTION(0, "GPIOD7"), + STM32_FUNCTION(1, "TRACED6"), + STM32_FUNCTION(4, "DFSDM_DATA4"), + STM32_FUNCTION(5, "I2C2_SCL"), + STM32_FUNCTION(7, "DFSDM_CK1"), + STM32_FUNCTION(8, "USART2_CK USART_BOOT2_CK"), + STM32_FUNCTION(10, "SPDIF_IN0"), + STM32_FUNCTION(11, "SDMMC3_D3"), + STM32_FUNCTION(13, "FMC_NE1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(56, "PD8"), + STM32_FUNCTION(0, "GPIOD8"), + STM32_FUNCTION(4, "DFSDM_CK3"), + STM32_FUNCTION(7, "SAI3_SCK_B"), + STM32_FUNCTION(8, "USART3_TX"), + STM32_FUNCTION(10, "SPDIF_IN1"), + STM32_FUNCTION(13, "FMC_D13"), + STM32_FUNCTION(15, "LCD_B7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(57, "PD9"), + STM32_FUNCTION(0, "GPIOD9"), + STM32_FUNCTION(4, "DFSDM_DATA3"), + STM32_FUNCTION(7, "SAI3_SD_B"), + STM32_FUNCTION(8, "USART3_RX"), + STM32_FUNCTION(10, "CAN2_RXFD"), + STM32_FUNCTION(13, "FMC_D14"), + STM32_FUNCTION(15, "LCD_B0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(58, "PD10"), + STM32_FUNCTION(0, "GPIOD10"), + STM32_FUNCTION(1, "RTC_REFIN"), + STM32_FUNCTION(2, "TIM16_BKIN"), + STM32_FUNCTION(4, "DFSDM_CKOUT"), + STM32_FUNCTION(5, "I2C5_SMBA"), + STM32_FUNCTION(6, "SPI3_MISO I2S3_SDI"), + STM32_FUNCTION(7, "SAI3_FS_B"), + STM32_FUNCTION(8, "USART3_CK USART_BOOT3_CK"), + STM32_FUNCTION(10, "CAN2_TXFD"), + STM32_FUNCTION(13, "FMC_D15"), + STM32_FUNCTION(15, "LCD_B3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(59, "PD11"), + STM32_FUNCTION(0, "GPIOD11"), + STM32_FUNCTION(4, "LPTIM2_IN2"), + STM32_FUNCTION(5, "I2C4_SMBA"), + STM32_FUNCTION(6, "I2C1_SMBA"), + STM32_FUNCTION(8, "USART3_CTS_NSS USART_BOOT3_CTS_NSS"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO0"), + STM32_FUNCTION(11, "SAI2_SD_A"), + STM32_FUNCTION(13, "FMC_A16 FMC_CLE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(60, "PD12"), + STM32_FUNCTION(0, "GPIOD12"), + STM32_FUNCTION(2, "LPTIM1_IN1"), + STM32_FUNCTION(3, "TIM4_CH1"), + STM32_FUNCTION(4, "LPTIM2_IN1"), + STM32_FUNCTION(5, "I2C4_SCL"), + STM32_FUNCTION(6, "I2C1_SCL"), + STM32_FUNCTION(8, "USART3_RTS USART_BOOT3_RTS"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO1"), + STM32_FUNCTION(11, "SAI2_FS_A"), + STM32_FUNCTION(13, "FMC_A17 FMC_ALE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(61, "PD13"), + STM32_FUNCTION(0, "GPIOD13"), + STM32_FUNCTION(2, "LPTIM1_OUT"), + STM32_FUNCTION(3, "TIM4_CH2"), + STM32_FUNCTION(5, "I2C4_SDA"), + STM32_FUNCTION(6, "I2C1_SDA"), + STM32_FUNCTION(7, "I2S3_MCK"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO3 QUADSPI_BOOTBK1_IO3"), + STM32_FUNCTION(11, "SAI2_SCK_A"), + STM32_FUNCTION(13, "FMC_A18"), + STM32_FUNCTION(14, "DSI_TE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(62, "PD14"), + STM32_FUNCTION(0, "GPIOD14"), + STM32_FUNCTION(3, "TIM4_CH3"), + STM32_FUNCTION(7, "SAI3_MCLK_B"), + STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), + STM32_FUNCTION(13, "FMC_D0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(63, "PD15"), + STM32_FUNCTION(0, "GPIOD15"), + STM32_FUNCTION(3, "TIM4_CH4"), + STM32_FUNCTION(7, "SAI3_MCLK_A"), + STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), + STM32_FUNCTION(13, "FMC_D1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(64, "PE0"), + STM32_FUNCTION(0, "GPIOE0"), + STM32_FUNCTION(2, "LPTIM1_ETR"), + STM32_FUNCTION(3, "TIM4_ETR"), + STM32_FUNCTION(5, "LPTIM2_ETR"), + STM32_FUNCTION(6, "SPI3_SCK I2S3_CK"), + STM32_FUNCTION(7, "SAI4_MCLK_B"), + STM32_FUNCTION(9, "UART8_RX UART_BOOT8_RX"), + STM32_FUNCTION(10, "CAN1_RXFD"), + STM32_FUNCTION(11, "SAI2_MCLK_A"), + STM32_FUNCTION(13, "FMC_NBL0"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(65, "PE1"), + STM32_FUNCTION(0, "GPIOE1"), + STM32_FUNCTION(2, "LPTIM1_IN2"), + STM32_FUNCTION(6, "I2S2_MCK"), + STM32_FUNCTION(7, "SAI3_SD_B"), + STM32_FUNCTION(9, "UART8_TX UART_BOOT8_TX"), + STM32_FUNCTION(10, "CAN1_TXFD"), + STM32_FUNCTION(13, "FMC_NBL1"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(66, "PE2"), + STM32_FUNCTION(0, "GPIOE2"), + STM32_FUNCTION(1, "TRACECLK"), + STM32_FUNCTION(3, "SAI1_CK1"), + STM32_FUNCTION(5, "I2C4_SCL"), + STM32_FUNCTION(6, "SPI4_SCK"), + STM32_FUNCTION(7, "SAI1_MCLK_A"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO2 QUADSPI_BOOTBK1_IO2"), + STM32_FUNCTION(12, "ETH_GMII_TXD3 ETH_MII_TXD3 ETH_RGMII_TXD3"), + STM32_FUNCTION(13, "FMC_A23"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(67, "PE3"), + STM32_FUNCTION(0, "GPIOE3"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(5, "TIM15_BKIN"), + STM32_FUNCTION(7, "SAI1_SD_B"), + STM32_FUNCTION(10, "SDMMC2_CK SDMMC_BOOT2_CK"), + STM32_FUNCTION(13, "FMC_A19"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(68, "PE4"), + STM32_FUNCTION(0, "GPIOE4"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(3, "SAI1_D2"), + STM32_FUNCTION(4, "DFSDM_DATA3"), + STM32_FUNCTION(5, "TIM15_CH1N"), + STM32_FUNCTION(6, "SPI4_NSS"), + STM32_FUNCTION(7, "SAI1_FS_A"), + STM32_FUNCTION(8, "SDMMC2_CKIN SDMMC_BOOT2_CKIN"), + STM32_FUNCTION(9, "SDMMC1_CKIN SDMMC_BOOT1_CKIN"), + STM32_FUNCTION(10, "SDMMC2_D4 SDMMC_BOOT2_D4"), + STM32_FUNCTION(12, "SDMMC1_D4 SDMMC_BOOT1_D4"), + STM32_FUNCTION(13, "FMC_A20"), + STM32_FUNCTION(14, "DCMI_D4"), + STM32_FUNCTION(15, "LCD_B0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(69, "PE5"), + STM32_FUNCTION(0, "GPIOE5"), + STM32_FUNCTION(1, "TRACED3"), + STM32_FUNCTION(3, "SAI1_CK2"), + STM32_FUNCTION(4, "DFSDM_CK3"), + STM32_FUNCTION(5, "TIM15_CH1"), + STM32_FUNCTION(6, "SPI4_MISO"), + STM32_FUNCTION(7, "SAI1_SCK_A"), + STM32_FUNCTION(8, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), + STM32_FUNCTION(9, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), + STM32_FUNCTION(10, "SDMMC2_D6 SDMMC_BOOT2_D6"), + STM32_FUNCTION(12, "SDMMC1_D6 SDMMC_BOOT1_D6"), + STM32_FUNCTION(13, "FMC_A21"), + STM32_FUNCTION(14, "DCMI_D6"), + STM32_FUNCTION(15, "LCD_G0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(70, "PE6"), + STM32_FUNCTION(0, "GPIOE6"), + STM32_FUNCTION(1, "TRACED2"), + STM32_FUNCTION(2, "TIM1_BKIN2"), + STM32_FUNCTION(3, "SAI1_D1"), + STM32_FUNCTION(5, "TIM15_CH2"), + STM32_FUNCTION(6, "SPI4_MOSI"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(8, "SDMMC2_D0"), + STM32_FUNCTION(9, "SDMMC1_D2 SDMMC_BOOT1_D2"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(13, "FMC_A22"), + STM32_FUNCTION(14, "DCMI_D7"), + STM32_FUNCTION(15, "LCD_G1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(71, "PE7"), + STM32_FUNCTION(0, "GPIOE7"), + STM32_FUNCTION(2, "TIM1_ETR"), + STM32_FUNCTION(3, "TIM3_ETR"), + STM32_FUNCTION(4, "DFSDM_DATA2"), + STM32_FUNCTION(8, "UART7_RX"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO0 QUADSPI_BOOTBK2_IO0"), + STM32_FUNCTION(13, "FMC_D4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(72, "PE8"), + STM32_FUNCTION(0, "GPIOE8"), + STM32_FUNCTION(2, "TIM1_CH1N"), + STM32_FUNCTION(4, "DFSDM_CK2"), + STM32_FUNCTION(8, "UART7_TX"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO1 QUADSPI_BOOTBK2_IO1"), + STM32_FUNCTION(13, "FMC_D5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(73, "PE9"), + STM32_FUNCTION(0, "GPIOE9"), + STM32_FUNCTION(2, "TIM1_CH1"), + STM32_FUNCTION(4, "DFSDM_CKOUT"), + STM32_FUNCTION(8, "UART7_RTS UART_BOOT7_RTS"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO2 QUADSPI_BOOTBK2_IO2"), + STM32_FUNCTION(13, "FMC_D6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(74, "PE10"), + STM32_FUNCTION(0, "GPIOE10"), + STM32_FUNCTION(2, "TIM1_CH2N"), + STM32_FUNCTION(4, "DFSDM_DATA4"), + STM32_FUNCTION(8, "UART7_CTS UART_BOOT7_CTS"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO3 QUADSPI_BOOTBK2_IO3"), + STM32_FUNCTION(13, "FMC_D7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(75, "PE11"), + STM32_FUNCTION(0, "GPIOE11"), + STM32_FUNCTION(2, "TIM1_CH2"), + STM32_FUNCTION(4, "DFSDM_CK4"), + STM32_FUNCTION(6, "SPI4_NSS"), + STM32_FUNCTION(8, "USART6_CK USART_BOOT6_CK"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(13, "FMC_D8"), + STM32_FUNCTION(15, "LCD_G3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(76, "PE12"), + STM32_FUNCTION(0, "GPIOE12"), + STM32_FUNCTION(2, "TIM1_CH3N"), + STM32_FUNCTION(4, "DFSDM_DATA5"), + STM32_FUNCTION(6, "SPI4_SCK"), + STM32_FUNCTION(9, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), + STM32_FUNCTION(11, "SAI2_SCK_B"), + STM32_FUNCTION(13, "FMC_D9"), + STM32_FUNCTION(15, "LCD_B4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(77, "PE13"), + STM32_FUNCTION(0, "GPIOE13"), + STM32_FUNCTION(1, "HDP2"), + STM32_FUNCTION(2, "TIM1_CH3"), + STM32_FUNCTION(4, "DFSDM_CK5"), + STM32_FUNCTION(6, "SPI4_MISO"), + STM32_FUNCTION(11, "SAI2_FS_B"), + STM32_FUNCTION(13, "FMC_D10"), + STM32_FUNCTION(15, "LCD_DE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(78, "PE14"), + STM32_FUNCTION(0, "GPIOE14"), + STM32_FUNCTION(2, "TIM1_CH4"), + STM32_FUNCTION(6, "SPI4_MOSI"), + STM32_FUNCTION(9, "UART8_RTS UART_BOOT8_RTS"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(12, "SDMMC1_D123DIR SDMMC_BOOT1_D123DIR"), + STM32_FUNCTION(13, "FMC_D11"), + STM32_FUNCTION(14, "LCD_G0"), + STM32_FUNCTION(15, "LCD_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(79, "PE15"), + STM32_FUNCTION(0, "GPIOE15"), + STM32_FUNCTION(1, "HDP3"), + STM32_FUNCTION(2, "TIM1_BKIN"), + STM32_FUNCTION(5, "TIM15_BKIN"), + STM32_FUNCTION(8, "USART2_CTS_NSS USART_BOOT2_CTS_NSS"), + STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), + STM32_FUNCTION(13, "FMC_D12"), + STM32_FUNCTION(15, "LCD_R7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(80, "PF0"), + STM32_FUNCTION(0, "GPIOF0"), + STM32_FUNCTION(5, "I2C2_SDA"), + STM32_FUNCTION(10, "SDMMC3_D0"), + STM32_FUNCTION(11, "SDMMC3_CKIN"), + STM32_FUNCTION(13, "FMC_A0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(81, "PF1"), + STM32_FUNCTION(0, "GPIOF1"), + STM32_FUNCTION(5, "I2C2_SCL"), + STM32_FUNCTION(10, "SDMMC3_CMD"), + STM32_FUNCTION(11, "SDMMC3_CDIR"), + STM32_FUNCTION(13, "FMC_A1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(82, "PF2"), + STM32_FUNCTION(0, "GPIOF2"), + STM32_FUNCTION(5, "I2C2_SMBA"), + STM32_FUNCTION(10, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), + STM32_FUNCTION(11, "SDMMC3_D0DIR"), + STM32_FUNCTION(12, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), + STM32_FUNCTION(13, "FMC_A2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(83, "PF3"), + STM32_FUNCTION(0, "GPIOF3"), + STM32_FUNCTION(12, "ETH_GMII_TX_ER ETH_MII_TX_ER"), + STM32_FUNCTION(13, "FMC_A3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(84, "PF4"), + STM32_FUNCTION(0, "GPIOF4"), + STM32_FUNCTION(8, "USART2_RX"), + STM32_FUNCTION(10, "SDMMC3_D1"), + STM32_FUNCTION(11, "SDMMC3_D123DIR"), + STM32_FUNCTION(13, "FMC_A4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(85, "PF5"), + STM32_FUNCTION(0, "GPIOF5"), + STM32_FUNCTION(8, "USART2_TX"), + STM32_FUNCTION(10, "SDMMC3_D2"), + STM32_FUNCTION(13, "FMC_A5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(86, "PF6"), + STM32_FUNCTION(0, "GPIOF6"), + STM32_FUNCTION(2, "TIM16_CH1"), + STM32_FUNCTION(6, "SPI5_NSS"), + STM32_FUNCTION(7, "SAI1_SD_B"), + STM32_FUNCTION(8, "UART7_RX UART_BOOT7_RX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO3 QUADSPI_BOOTBK1_IO3"), + STM32_FUNCTION(13, "SAI4_SCK_B"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(87, "PF7"), + STM32_FUNCTION(0, "GPIOF7"), + STM32_FUNCTION(2, "TIM17_CH1"), + STM32_FUNCTION(6, "SPI5_SCK"), + STM32_FUNCTION(7, "SAI1_MCLK_B"), + STM32_FUNCTION(8, "UART7_TX UART_BOOT7_TX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO2 QUADSPI_BOOTBK1_IO2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(88, "PF8"), + STM32_FUNCTION(0, "GPIOF8"), + STM32_FUNCTION(1, "TRACED12"), + STM32_FUNCTION(2, "TIM16_CH1N"), + STM32_FUNCTION(6, "SPI5_MISO"), + STM32_FUNCTION(7, "SAI1_SCK_B"), + STM32_FUNCTION(8, "UART7_RTS UART_BOOT7_RTS"), + STM32_FUNCTION(10, "TIM13_CH1"), + STM32_FUNCTION(11, "QUADSPI_BK1_IO0 QUADSPI_BOOTBK1_IO0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(89, "PF9"), + STM32_FUNCTION(0, "GPIOF9"), + STM32_FUNCTION(1, "TRACED13"), + STM32_FUNCTION(2, "TIM17_CH1N"), + STM32_FUNCTION(6, "SPI5_MOSI"), + STM32_FUNCTION(7, "SAI1_FS_B"), + STM32_FUNCTION(8, "UART7_CTS UART_BOOT7_CTS"), + STM32_FUNCTION(10, "TIM14_CH1"), + STM32_FUNCTION(11, "QUADSPI_BK1_IO1 QUADSPI_BOOTBK1_IO1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(90, "PF10"), + STM32_FUNCTION(0, "GPIOF10"), + STM32_FUNCTION(2, "TIM16_BKIN"), + STM32_FUNCTION(3, "SAI1_D3"), + STM32_FUNCTION(4, "SAI4_D4"), + STM32_FUNCTION(7, "SAI1_D4"), + STM32_FUNCTION(10, "QUADSPI_CLK QUADSPI_BOOTCLK"), + STM32_FUNCTION(13, "SAI4_D3"), + STM32_FUNCTION(14, "DCMI_D11"), + STM32_FUNCTION(15, "LCD_DE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(91, "PF11"), + STM32_FUNCTION(0, "GPIOF11"), + STM32_FUNCTION(6, "SPI5_MOSI"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(14, "DCMI_D12"), + STM32_FUNCTION(15, "LCD_G5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(92, "PF12"), + STM32_FUNCTION(0, "GPIOF12"), + STM32_FUNCTION(1, "TRACED4"), + STM32_FUNCTION(12, "ETH_GMII_RXD4"), + STM32_FUNCTION(13, "FMC_A6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(93, "PF13"), + STM32_FUNCTION(0, "GPIOF13"), + STM32_FUNCTION(1, "TRACED5"), + STM32_FUNCTION(4, "DFSDM_DATA6"), + STM32_FUNCTION(5, "I2C4_SMBA"), + STM32_FUNCTION(6, "I2C1_SMBA"), + STM32_FUNCTION(7, "DFSDM_DATA3"), + STM32_FUNCTION(12, "ETH_GMII_RXD5"), + STM32_FUNCTION(13, "FMC_A7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(94, "PF14"), + STM32_FUNCTION(0, "GPIOF14"), + STM32_FUNCTION(1, "TRACED6"), + STM32_FUNCTION(4, "DFSDM_CK6"), + STM32_FUNCTION(5, "I2C4_SCL"), + STM32_FUNCTION(6, "I2C1_SCL"), + STM32_FUNCTION(12, "ETH_GMII_RXD6"), + STM32_FUNCTION(13, "FMC_A8"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(95, "PF15"), + STM32_FUNCTION(0, "GPIOF15"), + STM32_FUNCTION(1, "TRACED7"), + STM32_FUNCTION(5, "I2C4_SDA"), + STM32_FUNCTION(6, "I2C1_SDA"), + STM32_FUNCTION(12, "ETH_GMII_RXD7"), + STM32_FUNCTION(13, "FMC_A9"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(96, "PG0"), + STM32_FUNCTION(0, "GPIOG0"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(4, "DFSDM_DATA0"), + STM32_FUNCTION(12, "ETH_GMII_TXD4"), + STM32_FUNCTION(13, "FMC_A10"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(97, "PG1"), + STM32_FUNCTION(0, "GPIOG1"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(12, "ETH_GMII_TXD5"), + STM32_FUNCTION(13, "FMC_A11"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(98, "PG2"), + STM32_FUNCTION(0, "GPIOG2"), + STM32_FUNCTION(1, "TRACED2"), + STM32_FUNCTION(2, "MCO2"), + STM32_FUNCTION(4, "TIM8_BKIN"), + STM32_FUNCTION(12, "ETH_GMII_TXD6"), + STM32_FUNCTION(13, "FMC_A12"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(99, "PG3"), + STM32_FUNCTION(0, "GPIOG3"), + STM32_FUNCTION(1, "TRACED3"), + STM32_FUNCTION(4, "TIM8_BKIN2"), + STM32_FUNCTION(5, "DFSDM_CK1"), + STM32_FUNCTION(12, "ETH_GMII_TXD7"), + STM32_FUNCTION(13, "FMC_A13"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(100, "PG4"), + STM32_FUNCTION(0, "GPIOG4"), + STM32_FUNCTION(2, "TIM1_BKIN2"), + STM32_FUNCTION(12, "ETH_GMII_GTX_CLK ETH_RGMII_GTX_CLK"), + STM32_FUNCTION(13, "FMC_A14"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(101, "PG5"), + STM32_FUNCTION(0, "GPIOG5"), + STM32_FUNCTION(2, "TIM1_ETR"), + STM32_FUNCTION(12, "ETH_GMII_CLK125 ETH_RGMII_CLK125"), + STM32_FUNCTION(13, "FMC_A15"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(102, "PG6"), + STM32_FUNCTION(0, "GPIOG6"), + STM32_FUNCTION(1, "TRACED14"), + STM32_FUNCTION(2, "TIM17_BKIN"), + STM32_FUNCTION(11, "SDMMC2_CMD SDMMC_BOOT2_CMD"), + STM32_FUNCTION(14, "DCMI_D12"), + STM32_FUNCTION(15, "LCD_R7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(103, "PG7"), + STM32_FUNCTION(0, "GPIOG7"), + STM32_FUNCTION(1, "TRACED5"), + STM32_FUNCTION(7, "SAI1_MCLK_A"), + STM32_FUNCTION(8, "USART6_CK USART_BOOT6_CK"), + STM32_FUNCTION(9, "UART8_RTS UART_BOOT8_RTS"), + STM32_FUNCTION(10, "QUADSPI_CLK"), + STM32_FUNCTION(12, "QUADSPI_BK2_IO3 QUADSPI_BOOTBK2_IO3"), + STM32_FUNCTION(13, "FMC_INT"), + STM32_FUNCTION(14, "DCMI_D13"), + STM32_FUNCTION(15, "LCD_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(104, "PG8"), + STM32_FUNCTION(0, "GPIOG8"), + STM32_FUNCTION(1, "TRACED15"), + STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), + STM32_FUNCTION(3, "ETH_CLK"), + STM32_FUNCTION(4, "TIM8_ETR"), + STM32_FUNCTION(6, "SPI6_NSS"), + STM32_FUNCTION(7, "SAI4_D2"), + STM32_FUNCTION(8, "USART6_RTS USART_BOOT6_RTS"), + STM32_FUNCTION(9, "USART3_RTS"), + STM32_FUNCTION(10, "SPDIF_IN2"), + STM32_FUNCTION(11, "SAI4_FS_A"), + STM32_FUNCTION(12, "ETH_PPS_OUT"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(105, "PG9"), + STM32_FUNCTION(0, "GPIOG9"), + STM32_FUNCTION(1, "DBTRGO"), + STM32_FUNCTION(8, "USART6_RX"), + STM32_FUNCTION(9, "SPDIF_IN3"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO2 QUADSPI_BOOTBK2_IO2"), + STM32_FUNCTION(11, "SAI2_FS_B"), + STM32_FUNCTION(13, "FMC_NE2 FMC_NCE"), + STM32_FUNCTION(14, "DCMI_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(106, "PG10"), + STM32_FUNCTION(0, "GPIOG10"), + STM32_FUNCTION(1, "TRACED10"), + STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), + STM32_FUNCTION(10, "LCD_G3"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(12, "QUADSPI_BK2_IO2 QUADSPI_BOOTBK2_IO2"), + STM32_FUNCTION(13, "FMC_NE3"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(107, "PG11"), + STM32_FUNCTION(0, "GPIOG11"), + STM32_FUNCTION(1, "TRACED11"), + STM32_FUNCTION(5, "USART1_TX"), + STM32_FUNCTION(7, "UART4_TX UART_BOOT4_TX"), + STM32_FUNCTION(9, "SPDIF_IN0"), + STM32_FUNCTION(12, "ETH_GMII_TX_EN ETH_MII_TX_EN ETH_RGMII_TX_CTL ETH_RMII_TX_EN"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(15, "LCD_B3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(108, "PG12"), + STM32_FUNCTION(0, "GPIOG12"), + STM32_FUNCTION(2, "LPTIM1_IN1"), + STM32_FUNCTION(6, "SPI6_MISO"), + STM32_FUNCTION(7, "SAI4_CK2"), + STM32_FUNCTION(8, "USART6_RTS USART_BOOT6_RTS"), + STM32_FUNCTION(9, "SPDIF_IN1"), + STM32_FUNCTION(10, "LCD_B4"), + STM32_FUNCTION(11, "SAI4_SCK_A"), + STM32_FUNCTION(12, "ETH_PHY_INTN"), + STM32_FUNCTION(13, "FMC_NE4"), + STM32_FUNCTION(15, "LCD_B1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(109, "PG13"), + STM32_FUNCTION(0, "GPIOG13"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(2, "LPTIM1_OUT"), + STM32_FUNCTION(3, "SAI1_CK2"), + STM32_FUNCTION(5, "SAI4_CK1"), + STM32_FUNCTION(6, "SPI6_SCK"), + STM32_FUNCTION(7, "SAI1_SCK_A"), + STM32_FUNCTION(8, "USART6_CTS_NSS USART_BOOT6_CTS_NSS"), + STM32_FUNCTION(11, "SAI4_MCLK_A"), + STM32_FUNCTION(12, "ETH_GMII_TXD0 ETH_MII_TXD0 ETH_RGMII_TXD0 ETH_RMII_TXD0"), + STM32_FUNCTION(13, "FMC_A24"), + STM32_FUNCTION(15, "LCD_R0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(110, "PG14"), + STM32_FUNCTION(0, "GPIOG14"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(2, "LPTIM1_ETR"), + STM32_FUNCTION(6, "SPI6_MOSI"), + STM32_FUNCTION(7, "SAI4_D1"), + STM32_FUNCTION(8, "USART6_TX"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO3 QUADSPI_BOOTBK2_IO3"), + STM32_FUNCTION(11, "SAI4_SD_A"), + STM32_FUNCTION(12, "ETH_GMII_TXD1 ETH_MII_TXD1 ETH_RGMII_TXD1 ETH_RMII_TXD1"), + STM32_FUNCTION(13, "FMC_A25"), + STM32_FUNCTION(15, "LCD_B0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(111, "PG15"), + STM32_FUNCTION(0, "GPIOG15"), + STM32_FUNCTION(1, "TRACED7"), + STM32_FUNCTION(3, "SAI1_D2"), + STM32_FUNCTION(5, "I2C2_SDA"), + STM32_FUNCTION(7, "SAI1_FS_A"), + STM32_FUNCTION(8, "USART6_CTS_NSS USART_BOOT6_CTS_NSS"), + STM32_FUNCTION(11, "SDMMC3_CK"), + STM32_FUNCTION(14, "DCMI_D13"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(112, "PH0"), + STM32_FUNCTION(0, "GPIOH0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(113, "PH1"), + STM32_FUNCTION(0, "GPIOH1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(114, "PH2"), + STM32_FUNCTION(0, "GPIOH2"), + STM32_FUNCTION(2, "LPTIM1_IN2"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO0 QUADSPI_BOOTBK2_IO0"), + STM32_FUNCTION(11, "SAI2_SCK_B"), + STM32_FUNCTION(12, "ETH_GMII_CRS ETH_MII_CRS"), + STM32_FUNCTION(15, "LCD_R0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(115, "PH3"), + STM32_FUNCTION(0, "GPIOH3"), + STM32_FUNCTION(4, "DFSDM_CK4"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO1 QUADSPI_BOOTBK2_IO1"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(12, "ETH_GMII_COL ETH_MII_COL"), + STM32_FUNCTION(15, "LCD_R1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(116, "PH4"), + STM32_FUNCTION(0, "GPIOH4"), + STM32_FUNCTION(5, "I2C2_SCL"), + STM32_FUNCTION(10, "LCD_G5"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(117, "PH5"), + STM32_FUNCTION(0, "GPIOH5"), + STM32_FUNCTION(5, "I2C2_SDA"), + STM32_FUNCTION(6, "SPI5_NSS"), + STM32_FUNCTION(13, "SAI4_SD_B"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(118, "PH6"), + STM32_FUNCTION(0, "GPIOH6"), + STM32_FUNCTION(3, "TIM12_CH1"), + STM32_FUNCTION(5, "I2C2_SMBA"), + STM32_FUNCTION(6, "SPI5_SCK"), + STM32_FUNCTION(12, "ETH_GMII_RXD2 ETH_MII_RXD2 ETH_RGMII_RXD2"), + STM32_FUNCTION(13, "MDIOS_MDIO"), + STM32_FUNCTION(14, "DCMI_D8"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(119, "PH7"), + STM32_FUNCTION(0, "GPIOH7"), + STM32_FUNCTION(5, "I2C3_SCL"), + STM32_FUNCTION(6, "SPI5_MISO"), + STM32_FUNCTION(12, "ETH_GMII_RXD3 ETH_MII_RXD3 ETH_RGMII_RXD3"), + STM32_FUNCTION(13, "MDIOS_MDC"), + STM32_FUNCTION(14, "DCMI_D9"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(120, "PH8"), + STM32_FUNCTION(0, "GPIOH8"), + STM32_FUNCTION(3, "TIM5_ETR"), + STM32_FUNCTION(5, "I2C3_SDA"), + STM32_FUNCTION(14, "DCMI_HSYNC"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(121, "PH9"), + STM32_FUNCTION(0, "GPIOH9"), + STM32_FUNCTION(3, "TIM12_CH2"), + STM32_FUNCTION(5, "I2C3_SMBA"), + STM32_FUNCTION(14, "DCMI_D0"), + STM32_FUNCTION(15, "LCD_R3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(122, "PH10"), + STM32_FUNCTION(0, "GPIOH10"), + STM32_FUNCTION(3, "TIM5_CH1"), + STM32_FUNCTION(5, "I2C4_SMBA"), + STM32_FUNCTION(6, "I2C1_SMBA"), + STM32_FUNCTION(14, "DCMI_D1"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(123, "PH11"), + STM32_FUNCTION(0, "GPIOH11"), + STM32_FUNCTION(3, "TIM5_CH2"), + STM32_FUNCTION(5, "I2C4_SCL"), + STM32_FUNCTION(6, "I2C1_SCL"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(124, "PH12"), + STM32_FUNCTION(0, "GPIOH12"), + STM32_FUNCTION(1, "HDP2"), + STM32_FUNCTION(3, "TIM5_CH3"), + STM32_FUNCTION(5, "I2C4_SDA"), + STM32_FUNCTION(6, "I2C1_SDA"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(15, "LCD_R6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(125, "PH13"), + STM32_FUNCTION(0, "GPIOH13"), + STM32_FUNCTION(4, "TIM8_CH1N"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(15, "LCD_G2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(126, "PH14"), + STM32_FUNCTION(0, "GPIOH14"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(14, "DCMI_D4"), + STM32_FUNCTION(15, "LCD_G3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(127, "PH15"), + STM32_FUNCTION(0, "GPIOH15"), + STM32_FUNCTION(4, "TIM8_CH3N"), + STM32_FUNCTION(10, "CAN1_TXFD"), + STM32_FUNCTION(14, "DCMI_D11"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(128, "PI0"), + STM32_FUNCTION(0, "GPIOI0"), + STM32_FUNCTION(3, "TIM5_CH4"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(10, "CAN1_RXFD"), + STM32_FUNCTION(14, "DCMI_D13"), + STM32_FUNCTION(15, "LCD_G5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(129, "PI1"), + STM32_FUNCTION(0, "GPIOI1"), + STM32_FUNCTION(4, "TIM8_BKIN2"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(14, "DCMI_D8"), + STM32_FUNCTION(15, "LCD_G6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(130, "PI2"), + STM32_FUNCTION(0, "GPIOI2"), + STM32_FUNCTION(4, "TIM8_CH4"), + STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"), + STM32_FUNCTION(14, "DCMI_D9"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(131, "PI3"), + STM32_FUNCTION(0, "GPIOI3"), + STM32_FUNCTION(4, "TIM8_ETR"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), + STM32_FUNCTION(14, "DCMI_D10"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(132, "PI4"), + STM32_FUNCTION(0, "GPIOI4"), + STM32_FUNCTION(4, "TIM8_BKIN"), + STM32_FUNCTION(11, "SAI2_MCLK_A"), + STM32_FUNCTION(14, "DCMI_D5"), + STM32_FUNCTION(15, "LCD_B4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(133, "PI5"), + STM32_FUNCTION(0, "GPIOI5"), + STM32_FUNCTION(4, "TIM8_CH1"), + STM32_FUNCTION(11, "SAI2_SCK_A"), + STM32_FUNCTION(14, "DCMI_VSYNC"), + STM32_FUNCTION(15, "LCD_B5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(134, "PI6"), + STM32_FUNCTION(0, "GPIOI6"), + STM32_FUNCTION(4, "TIM8_CH2"), + STM32_FUNCTION(11, "SAI2_SD_A"), + STM32_FUNCTION(14, "DCMI_D6"), + STM32_FUNCTION(15, "LCD_B6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(135, "PI7"), + STM32_FUNCTION(0, "GPIOI7"), + STM32_FUNCTION(4, "TIM8_CH3"), + STM32_FUNCTION(11, "SAI2_FS_A"), + STM32_FUNCTION(14, "DCMI_D7"), + STM32_FUNCTION(15, "LCD_B7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(136, "PI8"), + STM32_FUNCTION(0, "GPIOI8"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(137, "PI9"), + STM32_FUNCTION(0, "GPIOI9"), + STM32_FUNCTION(1, "HDP1"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(15, "LCD_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(138, "PI10"), + STM32_FUNCTION(0, "GPIOI10"), + STM32_FUNCTION(1, "HDP0"), + STM32_FUNCTION(9, "USART3_CTS_NSS USART_BOOT3_CTS_NSS"), + STM32_FUNCTION(10, "CAN1_RXFD"), + STM32_FUNCTION(12, "ETH_GMII_RX_ER ETH_MII_RX_ER"), + STM32_FUNCTION(15, "LCD_HSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(139, "PI11"), + STM32_FUNCTION(0, "GPIOI11"), + STM32_FUNCTION(1, "MCO1"), + STM32_FUNCTION(6, "I2S_CKIN"), + STM32_FUNCTION(10, "LCD_G6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(140, "PI12"), + STM32_FUNCTION(0, "GPIOI12"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(3, "HDP0"), + STM32_FUNCTION(15, "LCD_HSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(141, "PI13"), + STM32_FUNCTION(0, "GPIOI13"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(3, "HDP1"), + STM32_FUNCTION(15, "LCD_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(142, "PI14"), + STM32_FUNCTION(0, "GPIOI14"), + STM32_FUNCTION(1, "TRACECLK"), + STM32_FUNCTION(15, "LCD_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(143, "PI15"), + STM32_FUNCTION(0, "GPIOI15"), + STM32_FUNCTION(10, "LCD_G2"), + STM32_FUNCTION(15, "LCD_R0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(144, "PJ0"), + STM32_FUNCTION(0, "GPIOJ0"), + STM32_FUNCTION(1, "TRACED8"), + STM32_FUNCTION(10, "LCD_R7"), + STM32_FUNCTION(15, "LCD_R1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(145, "PJ1"), + STM32_FUNCTION(0, "GPIOJ1"), + STM32_FUNCTION(1, "TRACED9"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(146, "PJ2"), + STM32_FUNCTION(0, "GPIOJ2"), + STM32_FUNCTION(1, "TRACED10"), + STM32_FUNCTION(14, "DSI_TE"), + STM32_FUNCTION(15, "LCD_R3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(147, "PJ3"), + STM32_FUNCTION(0, "GPIOJ3"), + STM32_FUNCTION(1, "TRACED11"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(148, "PJ4"), + STM32_FUNCTION(0, "GPIOJ4"), + STM32_FUNCTION(1, "TRACED12"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(149, "PJ5"), + STM32_FUNCTION(0, "GPIOJ5"), + STM32_FUNCTION(1, "TRACED2"), + STM32_FUNCTION(3, "HDP2"), + STM32_FUNCTION(15, "LCD_R6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(150, "PJ6"), + STM32_FUNCTION(0, "GPIOJ6"), + STM32_FUNCTION(1, "TRACED3"), + STM32_FUNCTION(3, "HDP3"), + STM32_FUNCTION(4, "TIM8_CH2"), + STM32_FUNCTION(15, "LCD_R7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(151, "PJ7"), + STM32_FUNCTION(0, "GPIOJ7"), + STM32_FUNCTION(1, "TRACED13"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(15, "LCD_G0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(152, "PJ8"), + STM32_FUNCTION(0, "GPIOJ8"), + STM32_FUNCTION(1, "TRACED14"), + STM32_FUNCTION(2, "TIM1_CH3N"), + STM32_FUNCTION(4, "TIM8_CH1"), + STM32_FUNCTION(9, "UART8_TX"), + STM32_FUNCTION(15, "LCD_G1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(153, "PJ9"), + STM32_FUNCTION(0, "GPIOJ9"), + STM32_FUNCTION(1, "TRACED15"), + STM32_FUNCTION(2, "TIM1_CH3"), + STM32_FUNCTION(4, "TIM8_CH1N"), + STM32_FUNCTION(9, "UART8_RX"), + STM32_FUNCTION(15, "LCD_G2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(154, "PJ10"), + STM32_FUNCTION(0, "GPIOJ10"), + STM32_FUNCTION(2, "TIM1_CH2N"), + STM32_FUNCTION(4, "TIM8_CH2"), + STM32_FUNCTION(6, "SPI5_MOSI"), + STM32_FUNCTION(15, "LCD_G3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(155, "PJ11"), + STM32_FUNCTION(0, "GPIOJ11"), + STM32_FUNCTION(2, "TIM1_CH2"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(6, "SPI5_MISO"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(156, "PJ12"), + STM32_FUNCTION(0, "GPIOJ12"), + STM32_FUNCTION(10, "LCD_G3"), + STM32_FUNCTION(15, "LCD_B0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(157, "PJ13"), + STM32_FUNCTION(0, "GPIOJ13"), + STM32_FUNCTION(10, "LCD_G4"), + STM32_FUNCTION(15, "LCD_B1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(158, "PJ14"), + STM32_FUNCTION(0, "GPIOJ14"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(159, "PJ15"), + STM32_FUNCTION(0, "GPIOJ15"), + STM32_FUNCTION(15, "LCD_B3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(160, "PK0"), + STM32_FUNCTION(0, "GPIOK0"), + STM32_FUNCTION(2, "TIM1_CH1N"), + STM32_FUNCTION(4, "TIM8_CH3"), + STM32_FUNCTION(6, "SPI5_SCK"), + STM32_FUNCTION(15, "LCD_G5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(161, "PK1"), + STM32_FUNCTION(0, "GPIOK1"), + STM32_FUNCTION(1, "TRACED4"), + STM32_FUNCTION(2, "TIM1_CH1"), + STM32_FUNCTION(3, "HDP4"), + STM32_FUNCTION(4, "TIM8_CH3N"), + STM32_FUNCTION(6, "SPI5_NSS"), + STM32_FUNCTION(15, "LCD_G6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(162, "PK2"), + STM32_FUNCTION(0, "GPIOK2"), + STM32_FUNCTION(1, "TRACED5"), + STM32_FUNCTION(2, "TIM1_BKIN"), + STM32_FUNCTION(3, "HDP5"), + STM32_FUNCTION(4, "TIM8_BKIN"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(163, "PK3"), + STM32_FUNCTION(0, "GPIOK3"), + STM32_FUNCTION(15, "LCD_B4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(164, "PK4"), + STM32_FUNCTION(0, "GPIOK4"), + STM32_FUNCTION(15, "LCD_B5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(165, "PK5"), + STM32_FUNCTION(0, "GPIOK5"), + STM32_FUNCTION(1, "TRACED6"), + STM32_FUNCTION(3, "HDP6"), + STM32_FUNCTION(15, "LCD_B6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(166, "PK6"), + STM32_FUNCTION(0, "GPIOK6"), + STM32_FUNCTION(1, "TRACED7"), + STM32_FUNCTION(3, "HDP7"), + STM32_FUNCTION(15, "LCD_B7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(167, "PK7"), + STM32_FUNCTION(0, "GPIOK7"), + STM32_FUNCTION(15, "LCD_DE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), +}; + +static const struct stm32_desc_pin stm32mp157_z_pins[] = { + STM32_PIN( + PINCTRL_PIN(400, "PZ0"), + STM32_FUNCTION(0, "GPIOZ0"), + STM32_FUNCTION(3, "I2C6_SCL"), + STM32_FUNCTION(4, "I2C2_SCL"), + STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"), + STM32_FUNCTION(8, "USART1_CK"), + STM32_FUNCTION(9, "SPI6_SCK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(401, "PZ1"), + STM32_FUNCTION(0, "GPIOZ1"), + STM32_FUNCTION(3, "I2C6_SDA"), + STM32_FUNCTION(4, "I2C2_SDA"), + STM32_FUNCTION(5, "I2C5_SDA"), + STM32_FUNCTION(6, "SPI1_MISO I2S1_SDI"), + STM32_FUNCTION(7, "I2C4_SDA"), + STM32_FUNCTION(8, "USART1_RX"), + STM32_FUNCTION(9, "SPI6_MISO"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(402, "PZ2"), + STM32_FUNCTION(0, "GPIOZ2"), + STM32_FUNCTION(3, "I2C6_SCL"), + STM32_FUNCTION(4, "I2C2_SCL"), + STM32_FUNCTION(5, "I2C5_SMBA"), + STM32_FUNCTION(6, "SPI1_MOSI I2S1_SDO"), + STM32_FUNCTION(7, "I2C4_SMBA"), + STM32_FUNCTION(8, "USART1_TX"), + STM32_FUNCTION(9, "SPI6_MOSI"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(403, "PZ3"), + STM32_FUNCTION(0, "GPIOZ3"), + STM32_FUNCTION(3, "I2C6_SDA"), + STM32_FUNCTION(4, "I2C2_SDA"), + STM32_FUNCTION(5, "I2C5_SDA"), + STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), + STM32_FUNCTION(7, "I2C4_SDA"), + STM32_FUNCTION(8, "USART1_CTS_NSS"), + STM32_FUNCTION(9, "SPI6_NSS"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(404, "PZ4"), + STM32_FUNCTION(0, "GPIOZ4"), + STM32_FUNCTION(3, "I2C6_SCL"), + STM32_FUNCTION(4, "I2C2_SCL"), + STM32_FUNCTION(5, "I2C5_SCL"), + STM32_FUNCTION(7, "I2C4_SCL"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(405, "PZ5"), + STM32_FUNCTION(0, "GPIOZ5"), + STM32_FUNCTION(3, "I2C6_SDA"), + STM32_FUNCTION(4, "I2C2_SDA"), + STM32_FUNCTION(5, "I2C5_SDA"), + STM32_FUNCTION(7, "I2C4_SDA"), + STM32_FUNCTION(8, "USART1_RTS"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(406, "PZ6"), + STM32_FUNCTION(0, "GPIOZ6"), + STM32_FUNCTION(3, "I2C6_SCL"), + STM32_FUNCTION(4, "I2C2_SCL"), + STM32_FUNCTION(5, "USART1_CK"), + STM32_FUNCTION(6, "I2S1_MCK"), + STM32_FUNCTION(7, "I2C4_SMBA"), + STM32_FUNCTION(8, "USART1_RX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(407, "PZ7"), + STM32_FUNCTION(0, "GPIOZ7"), + STM32_FUNCTION(3, "I2C6_SDA"), + STM32_FUNCTION(4, "I2C2_SDA"), + STM32_FUNCTION(8, "USART1_TX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), +}; + +static struct stm32_pinctrl_match_data stm32mp157_match_data = { + .pins = stm32mp157_pins, + .npins = ARRAY_SIZE(stm32mp157_pins), +}; + +static struct stm32_pinctrl_match_data stm32mp157_z_match_data = { + .pins = stm32mp157_z_pins, + .npins = ARRAY_SIZE(stm32mp157_z_pins), +}; + +static const struct of_device_id stm32mp157_pctrl_match[] = { + { + .compatible = "st,stm32mp157-pinctrl", + .data = &stm32mp157_match_data, + }, + { + .compatible = "st,stm32mp157-z-pinctrl", + .data = &stm32mp157_z_match_data, + }, + { } +}; + +static struct platform_driver stm32mp157_pinctrl_driver = { + .probe = stm32_pctl_probe, + .driver = { + .name = "stm32mp157-pinctrl", + .of_match_table = stm32mp157_pctrl_match, + }, +}; + +static int __init stm32mp157_pinctrl_init(void) +{ + return platform_driver_register(&stm32mp157_pinctrl_driver); +} +arch_initcall(stm32mp157_pinctrl_init); -- cgit From e3fd24a574041785bad4487595228e8b02c92e41 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 12 Dec 2017 14:24:19 +0800 Subject: pinctrl: mediatek: cleanup for placing all drivers under the menu Since lots of MediaTek drivers had been added, it seems slightly better for that adding cleanup for placing MediaTek pinctrl drivers under the independent menu as other kinds of drivers usually was done. Signed-off-by: Sean Wang Reviewed-by: Biao Huang Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index fac9866311f3..03b3023d5fe5 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -1,4 +1,5 @@ -if ARCH_MEDIATEK || COMPILE_TEST +menu "MediaTek pinctrl drivers" + depends on ARCH_MEDIATEK || COMPILE_TEST config PINCTRL_MTK bool @@ -46,4 +47,4 @@ config PINCTRL_MT6397 default MFD_MT6397 select PINCTRL_MTK -endif +endmenu -- cgit From d6ed935513202e1922071979bee96777f9c37229 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 12 Dec 2017 14:24:20 +0800 Subject: pinctrl: mediatek: add pinctrl driver for MT7622 SoC Add support for pinctrl on MT7622 SoC. The IO core found on the SoC has the registers for pinctrl, pinconf and gpio mixed up in the same register range. However, the IO core for the MT7622 SoC is completely distinct from anyone of previous MediaTek SoCs which already had support, such as the hardware internal, register address map and register detailed definition for each pin. Therefore, instead, the driver is being newly implemented by reusing generic methods provided from the core layer with GENERIC_PINCONF, GENERIC_PINCTRL_GROUPS, and GENERIC_PINMUX_FUNCTIONS for the sake of code simplicity and rid of superfluous code. Where the function of pins determined by groups is utilized in this driver which can help developers less confused with what combinations of pins effective on the SoC and even reducing the mistakes during the integration of those relevant boards. As the gpio_chip handling is also only a few lines, the driver also implements the gpio functionality directly through GPIOLIB. Signed-off-by: Sean Wang Reviewed-by: Biao Huang Signed-off-by: Linus Walleij --- drivers/pinctrl/Makefile | 2 +- drivers/pinctrl/mediatek/Kconfig | 10 + drivers/pinctrl/mediatek/Makefile | 3 +- drivers/pinctrl/mediatek/pinctrl-mt7622.c | 1595 +++++++++++++++++++++++++++++ 4 files changed, 1608 insertions(+), 2 deletions(-) create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt7622.c (limited to 'drivers') diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 4777f1595ce2..2341228eb718 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -65,5 +65,5 @@ obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ obj-y += ti/ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ -obj-$(CONFIG_PINCTRL_MTK) += mediatek/ +obj-y += mediatek/ obj-$(CONFIG_PINCTRL_ZX) += zte/ diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index 03b3023d5fe5..3e598740b379 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -32,6 +32,16 @@ config PINCTRL_MT8127 select PINCTRL_MTK # For ARMv8 SoCs +config PINCTRL_MT7622 + bool "MediaTek MT7622 pin control" + depends on OF + depends on ARM64 || COMPILE_TEST + select GENERIC_PINCONF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GPIOLIB + select OF_GPIO + config PINCTRL_MT8173 bool "Mediatek MT8173 pin control" depends on OF diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile index 10d90140a38a..ed7d2b2cc6e9 100644 --- a/drivers/pinctrl/mediatek/Makefile +++ b/drivers/pinctrl/mediatek/Makefile @@ -1,10 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 # Core -obj-y += pinctrl-mtk-common.o +obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o # SoC Drivers obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o +obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c new file mode 100644 index 000000000000..3824d82888ac --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c @@ -0,0 +1,1595 @@ +/* + * MediaTek MT7622 Pinctrl Driver + * + * Copyright (C) 2017 Sean Wang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../pinconf.h" +#include "../pinmux.h" + +#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME +#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), } +#define PINCTRL_PIN_GROUP(name, id) \ + { \ + name, \ + id##_pins, \ + ARRAY_SIZE(id##_pins), \ + id##_funcs, \ + } + +#define MTK_GPIO_MODE 1 +#define MTK_INPUT 0 +#define MTK_OUTPUT 1 +#define MTK_DISABLE 0 +#define MTK_ENABLE 1 + +/* Custom pinconf parameters */ +#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) +#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) + +/* List these attributes which could be modified for the pin */ +enum { + PINCTRL_PIN_REG_MODE, + PINCTRL_PIN_REG_DIR, + PINCTRL_PIN_REG_DI, + PINCTRL_PIN_REG_DO, + PINCTRL_PIN_REG_SR, + PINCTRL_PIN_REG_SMT, + PINCTRL_PIN_REG_PD, + PINCTRL_PIN_REG_PU, + PINCTRL_PIN_REG_E4, + PINCTRL_PIN_REG_E8, + PINCTRL_PIN_REG_TDSEL, + PINCTRL_PIN_REG_RDSEL, + PINCTRL_PIN_REG_MAX, +}; + +/* struct mtk_pin_field - the structure that holds the information of the field + * used to describe the attribute for the pin + * @offset: the register offset relative to the base address + * @mask: the mask used to filter out the field from the register + * @bitpos: the start bit relative to the register + * @next: the indication that the field would be extended to the + next register + */ +struct mtk_pin_field { + u32 offset; + u32 mask; + u8 bitpos; + u8 next; +}; + +/* struct mtk_pin_field_calc - the structure that holds the range providing + * the guide used to look up the relevant field + * @s_pin: the start pin within the range + * @e_pin: the end pin within the range + * @s_addr: the start address for the range + * @x_addrs: the address distance between two consecutive registers + * within the range + * @s_bit: the start bit for the first register within the range + * @x_bits: the bit distance between two consecutive pins within + * the range + */ +struct mtk_pin_field_calc { + u16 s_pin; + u16 e_pin; + u32 s_addr; + u8 x_addrs; + u8 s_bit; + u8 x_bits; +}; + +/* struct mtk_pin_reg_calc - the structure that holds all ranges used to + * determine which register the pin would make use of + * for certain pin attribute. + * @range: the start address for the range + * @nranges: the number of items in the range + */ +struct mtk_pin_reg_calc { + const struct mtk_pin_field_calc *range; + unsigned int nranges; +}; + +/* struct mtk_pin_soc - the structure that holds SoC-specific data */ +struct mtk_pin_soc { + const struct mtk_pin_reg_calc *reg_cal; + const struct pinctrl_pin_desc *pins; + unsigned int npins; + const struct group_desc *grps; + unsigned int ngrps; + const struct function_desc *funcs; + unsigned int nfuncs; +}; + +struct mtk_pinctrl { + struct pinctrl_dev *pctrl; + void __iomem *base; + struct device *dev; + struct gpio_chip chip; + const struct mtk_pin_soc *soc; +}; + +static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = { + {0, 0, 0x320, 0x10, 16, 4}, + {1, 4, 0x3a0, 0x10, 16, 4}, + {5, 5, 0x320, 0x10, 0, 4}, + {6, 6, 0x300, 0x10, 4, 4}, + {7, 7, 0x300, 0x10, 4, 4}, + {8, 9, 0x350, 0x10, 20, 4}, + {10, 10, 0x300, 0x10, 8, 4}, + {11, 11, 0x300, 0x10, 8, 4}, + {12, 12, 0x300, 0x10, 8, 4}, + {13, 13, 0x300, 0x10, 8, 4}, + {14, 15, 0x320, 0x10, 4, 4}, + {16, 17, 0x320, 0x10, 20, 4}, + {18, 21, 0x310, 0x10, 16, 4}, + {22, 22, 0x380, 0x10, 16, 4}, + {23, 23, 0x300, 0x10, 24, 4}, + {24, 24, 0x300, 0x10, 24, 4}, + {25, 25, 0x300, 0x10, 12, 4}, + {25, 25, 0x300, 0x10, 12, 4}, + {26, 26, 0x300, 0x10, 12, 4}, + {27, 27, 0x300, 0x10, 12, 4}, + {28, 28, 0x300, 0x10, 12, 4}, + {29, 29, 0x300, 0x10, 12, 4}, + {30, 30, 0x300, 0x10, 12, 4}, + {31, 31, 0x300, 0x10, 12, 4}, + {32, 32, 0x300, 0x10, 12, 4}, + {33, 33, 0x300, 0x10, 12, 4}, + {34, 34, 0x300, 0x10, 12, 4}, + {35, 35, 0x300, 0x10, 12, 4}, + {36, 36, 0x300, 0x10, 12, 4}, + {37, 37, 0x300, 0x10, 20, 4}, + {38, 38, 0x300, 0x10, 20, 4}, + {39, 39, 0x300, 0x10, 20, 4}, + {40, 40, 0x300, 0x10, 20, 4}, + {41, 41, 0x300, 0x10, 20, 4}, + {42, 42, 0x300, 0x10, 20, 4}, + {43, 43, 0x300, 0x10, 20, 4}, + {44, 44, 0x300, 0x10, 20, 4}, + {45, 46, 0x300, 0x10, 20, 4}, + {47, 47, 0x300, 0x10, 20, 4}, + {48, 48, 0x300, 0x10, 20, 4}, + {49, 49, 0x300, 0x10, 20, 4}, + {50, 50, 0x300, 0x10, 20, 4}, + {51, 70, 0x330, 0x10, 4, 4}, + {71, 71, 0x300, 0x10, 16, 4}, + {72, 72, 0x300, 0x10, 16, 4}, + {73, 76, 0x310, 0x10, 0, 4}, + {77, 77, 0x320, 0x10, 28, 4}, + {78, 78, 0x320, 0x10, 12, 4}, + {79, 82, 0x3a0, 0x10, 0, 4}, + {83, 83, 0x350, 0x10, 28, 4}, + {84, 84, 0x330, 0x10, 0, 4}, + {85, 90, 0x360, 0x10, 4, 4}, + {91, 94, 0x390, 0x10, 16, 4}, + {95, 97, 0x380, 0x10, 20, 4}, + {98, 101, 0x390, 0x10, 0, 4}, + {102, 102, 0x360, 0x10, 0, 4}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_dir_range[] = { + {0, 102, 0x0, 0x10, 0, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_di_range[] = { + {0, 102, 0x200, 0x10, 0, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_do_range[] = { + {0, 102, 0x100, 0x10, 0, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_sr_range[] = { + {0, 31, 0x910, 0x10, 0, 1}, + {32, 50, 0xa10, 0x10, 0, 1}, + {51, 70, 0x810, 0x10, 0, 1}, + {71, 72, 0xb10, 0x10, 0, 1}, + {73, 86, 0xb10, 0x10, 4, 1}, + {87, 90, 0xc10, 0x10, 0, 1}, + {91, 102, 0xb10, 0x10, 18, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_smt_range[] = { + {0, 31, 0x920, 0x10, 0, 1}, + {32, 50, 0xa20, 0x10, 0, 1}, + {51, 70, 0x820, 0x10, 0, 1}, + {71, 72, 0xb20, 0x10, 0, 1}, + {73, 86, 0xb20, 0x10, 4, 1}, + {87, 90, 0xc20, 0x10, 0, 1}, + {91, 102, 0xb20, 0x10, 18, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_pu_range[] = { + {0, 31, 0x930, 0x10, 0, 1}, + {32, 50, 0xa30, 0x10, 0, 1}, + {51, 70, 0x830, 0x10, 0, 1}, + {71, 72, 0xb30, 0x10, 0, 1}, + {73, 86, 0xb30, 0x10, 4, 1}, + {87, 90, 0xc30, 0x10, 0, 1}, + {91, 102, 0xb30, 0x10, 18, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_pd_range[] = { + {0, 31, 0x940, 0x10, 0, 1}, + {32, 50, 0xa40, 0x10, 0, 1}, + {51, 70, 0x840, 0x10, 0, 1}, + {71, 72, 0xb40, 0x10, 0, 1}, + {73, 86, 0xb40, 0x10, 4, 1}, + {87, 90, 0xc40, 0x10, 0, 1}, + {91, 102, 0xb40, 0x10, 18, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_e4_range[] = { + {0, 31, 0x960, 0x10, 0, 1}, + {32, 50, 0xa60, 0x10, 0, 1}, + {51, 70, 0x860, 0x10, 0, 1}, + {71, 72, 0xb60, 0x10, 0, 1}, + {73, 86, 0xb60, 0x10, 4, 1}, + {87, 90, 0xc60, 0x10, 0, 1}, + {91, 102, 0xb60, 0x10, 18, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_e8_range[] = { + {0, 31, 0x970, 0x10, 0, 1}, + {32, 50, 0xa70, 0x10, 0, 1}, + {51, 70, 0x870, 0x10, 0, 1}, + {71, 72, 0xb70, 0x10, 0, 1}, + {73, 86, 0xb70, 0x10, 4, 1}, + {87, 90, 0xc70, 0x10, 0, 1}, + {91, 102, 0xb70, 0x10, 18, 1}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_tdsel_range[] = { + {0, 31, 0x980, 0x4, 0, 4}, + {32, 50, 0xa80, 0x4, 0, 4}, + {51, 70, 0x880, 0x4, 0, 4}, + {71, 72, 0xb80, 0x4, 0, 4}, + {73, 86, 0xb80, 0x4, 16, 4}, + {87, 90, 0xc80, 0x4, 0, 4}, + {91, 102, 0xb88, 0x4, 8, 4}, +}; + +static const struct mtk_pin_field_calc mt7622_pin_rdsel_range[] = { + {0, 31, 0x990, 0x4, 0, 6}, + {32, 50, 0xa90, 0x4, 0, 6}, + {51, 58, 0x890, 0x4, 0, 6}, + {59, 60, 0x894, 0x4, 28, 6}, + {61, 62, 0x894, 0x4, 16, 6}, + {63, 66, 0x898, 0x4, 8, 6}, + {67, 68, 0x89c, 0x4, 12, 6}, + {69, 70, 0x89c, 0x4, 0, 6}, + {71, 72, 0xb90, 0x4, 0, 6}, + {73, 86, 0xb90, 0x4, 24, 6}, + {87, 90, 0xc90, 0x4, 0, 6}, + {91, 102, 0xb9c, 0x4, 12, 6}, +}; + +static const struct mtk_pin_reg_calc mt7622_reg_cals[PINCTRL_PIN_REG_MAX] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7622_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7622_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7622_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7622_pin_do_range), + [PINCTRL_PIN_REG_SR] = MTK_RANGE(mt7622_pin_sr_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7622_pin_smt_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7622_pin_pu_range), + [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7622_pin_pd_range), + [PINCTRL_PIN_REG_E4] = MTK_RANGE(mt7622_pin_e4_range), + [PINCTRL_PIN_REG_E8] = MTK_RANGE(mt7622_pin_e8_range), + [PINCTRL_PIN_REG_TDSEL] = MTK_RANGE(mt7622_pin_tdsel_range), + [PINCTRL_PIN_REG_RDSEL] = MTK_RANGE(mt7622_pin_rdsel_range), +}; + +static const struct pinctrl_pin_desc mt7622_pins[] = { + PINCTRL_PIN(0, "GPIO_A"), + PINCTRL_PIN(1, "I2S1_IN"), + PINCTRL_PIN(2, "I2S1_OUT"), + PINCTRL_PIN(3, "I2S_BCLK"), + PINCTRL_PIN(4, "I2S_WS"), + PINCTRL_PIN(5, "I2S_MCLK"), + PINCTRL_PIN(6, "TXD0"), + PINCTRL_PIN(7, "RXD0"), + PINCTRL_PIN(8, "SPI_WP"), + PINCTRL_PIN(9, "SPI_HOLD"), + PINCTRL_PIN(10, "SPI_CLK"), + PINCTRL_PIN(11, "SPI_MOSI"), + PINCTRL_PIN(12, "SPI_MISO"), + PINCTRL_PIN(13, "SPI_CS"), + PINCTRL_PIN(14, "I2C_SDA"), + PINCTRL_PIN(15, "I2C_SCL"), + PINCTRL_PIN(16, "I2S2_IN"), + PINCTRL_PIN(17, "I2S3_IN"), + PINCTRL_PIN(18, "I2S4_IN"), + PINCTRL_PIN(19, "I2S2_OUT"), + PINCTRL_PIN(20, "I2S3_OUT"), + PINCTRL_PIN(21, "I2S4_OUT"), + PINCTRL_PIN(22, "GPIO_B"), + PINCTRL_PIN(23, "MDC"), + PINCTRL_PIN(24, "MDIO"), + PINCTRL_PIN(25, "G2_TXD0"), + PINCTRL_PIN(26, "G2_TXD1"), + PINCTRL_PIN(27, "G2_TXD2"), + PINCTRL_PIN(28, "G2_TXD3"), + PINCTRL_PIN(29, "G2_TXEN"), + PINCTRL_PIN(30, "G2_TXC"), + PINCTRL_PIN(31, "G2_RXD0"), + PINCTRL_PIN(32, "G2_RXD1"), + PINCTRL_PIN(33, "G2_RXD2"), + PINCTRL_PIN(34, "G2_RXD3"), + PINCTRL_PIN(35, "G2_RXDV"), + PINCTRL_PIN(36, "G2_RXC"), + PINCTRL_PIN(37, "NCEB"), + PINCTRL_PIN(38, "NWEB"), + PINCTRL_PIN(39, "NREB"), + PINCTRL_PIN(40, "NDL4"), + PINCTRL_PIN(41, "NDL5"), + PINCTRL_PIN(42, "NDL6"), + PINCTRL_PIN(43, "NDL7"), + PINCTRL_PIN(44, "NRB"), + PINCTRL_PIN(45, "NCLE"), + PINCTRL_PIN(46, "NALE"), + PINCTRL_PIN(47, "NDL0"), + PINCTRL_PIN(48, "NDL1"), + PINCTRL_PIN(49, "NDL2"), + PINCTRL_PIN(50, "NDL3"), + PINCTRL_PIN(51, "MDI_TP_P0"), + PINCTRL_PIN(52, "MDI_TN_P0"), + PINCTRL_PIN(53, "MDI_RP_P0"), + PINCTRL_PIN(54, "MDI_RN_P0"), + PINCTRL_PIN(55, "MDI_TP_P1"), + PINCTRL_PIN(56, "MDI_TN_P1"), + PINCTRL_PIN(57, "MDI_RP_P1"), + PINCTRL_PIN(58, "MDI_RN_P1"), + PINCTRL_PIN(59, "MDI_RP_P2"), + PINCTRL_PIN(60, "MDI_RN_P2"), + PINCTRL_PIN(61, "MDI_TP_P2"), + PINCTRL_PIN(62, "MDI_TN_P2"), + PINCTRL_PIN(63, "MDI_TP_P3"), + PINCTRL_PIN(64, "MDI_TN_P3"), + PINCTRL_PIN(65, "MDI_RP_P3"), + PINCTRL_PIN(66, "MDI_RN_P3"), + PINCTRL_PIN(67, "MDI_RP_P4"), + PINCTRL_PIN(68, "MDI_RN_P4"), + PINCTRL_PIN(69, "MDI_TP_P4"), + PINCTRL_PIN(70, "MDI_TN_P4"), + PINCTRL_PIN(71, "PMIC_SCL"), + PINCTRL_PIN(72, "PMIC_SDA"), + PINCTRL_PIN(73, "SPIC1_CLK"), + PINCTRL_PIN(74, "SPIC1_MOSI"), + PINCTRL_PIN(75, "SPIC1_MISO"), + PINCTRL_PIN(76, "SPIC1_CS"), + PINCTRL_PIN(77, "GPIO_D"), + PINCTRL_PIN(78, "WATCHDOG"), + PINCTRL_PIN(79, "RTS3_N"), + PINCTRL_PIN(80, "CTS3_N"), + PINCTRL_PIN(81, "TXD3"), + PINCTRL_PIN(82, "RXD3"), + PINCTRL_PIN(83, "PERST0_N"), + PINCTRL_PIN(84, "PERST1_N"), + PINCTRL_PIN(85, "WLED_N"), + PINCTRL_PIN(86, "EPHY_LED0_N"), + PINCTRL_PIN(87, "AUXIN0"), + PINCTRL_PIN(88, "AUXIN1"), + PINCTRL_PIN(89, "AUXIN2"), + PINCTRL_PIN(90, "AUXIN3"), + PINCTRL_PIN(91, "TXD4"), + PINCTRL_PIN(92, "RXD4"), + PINCTRL_PIN(93, "RTS4_N"), + PINCTRL_PIN(94, "CTS4_N"), + PINCTRL_PIN(95, "PWM1"), + PINCTRL_PIN(96, "PWM2"), + PINCTRL_PIN(97, "PWM3"), + PINCTRL_PIN(98, "PWM4"), + PINCTRL_PIN(99, "PWM5"), + PINCTRL_PIN(100, "PWM6"), + PINCTRL_PIN(101, "PWM7"), + PINCTRL_PIN(102, "GPIO_E"), +}; + +/* List all groups consisting of these pins dedicated to the enablement of + * certain hardware block and the corresponding mode for all of the pins. The + * hardware probably has multiple combinations of these pinouts. + */ + +/* EMMC */ +static int mt7622_emmc_pins[] = { 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, }; +static int mt7622_emmc_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; + +static int mt7622_emmc_rst_pins[] = { 37, }; +static int mt7622_emmc_rst_funcs[] = { 1, }; + +/* LED for EPHY */ +static int mt7622_ephy_leds_pins[] = { 86, 91, 92, 93, 94, }; +static int mt7622_ephy_leds_funcs[] = { 0, 0, 0, 0, 0, }; +static int mt7622_ephy0_led_pins[] = { 86, }; +static int mt7622_ephy0_led_funcs[] = { 0, }; +static int mt7622_ephy1_led_pins[] = { 91, }; +static int mt7622_ephy1_led_funcs[] = { 2, }; +static int mt7622_ephy2_led_pins[] = { 92, }; +static int mt7622_ephy2_led_funcs[] = { 2, }; +static int mt7622_ephy3_led_pins[] = { 93, }; +static int mt7622_ephy3_led_funcs[] = { 2, }; +static int mt7622_ephy4_led_pins[] = { 94, }; +static int mt7622_ephy4_led_funcs[] = { 2, }; + +/* Embedded Switch */ +static int mt7622_esw_pins[] = { 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, }; +static int mt7622_esw_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, }; +static int mt7622_esw_p0_p1_pins[] = { 51, 52, 53, 54, 55, 56, 57, 58, }; +static int mt7622_esw_p0_p1_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, }; +static int mt7622_esw_p2_p3_p4_pins[] = { 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, }; +static int mt7622_esw_p2_p3_p4_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, }; +/* RGMII via ESW */ +static int mt7622_rgmii_via_esw_pins[] = { 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, }; +static int mt7622_rgmii_via_esw_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, }; + +/* RGMII via GMAC1 */ +static int mt7622_rgmii_via_gmac1_pins[] = { 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, }; +static int mt7622_rgmii_via_gmac1_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, }; + +/* RGMII via GMAC2 */ +static int mt7622_rgmii_via_gmac2_pins[] = { 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, }; +static int mt7622_rgmii_via_gmac2_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, }; + +/* I2C */ +static int mt7622_i2c0_pins[] = { 14, 15, }; +static int mt7622_i2c0_funcs[] = { 0, 0, }; +static int mt7622_i2c1_0_pins[] = { 55, 56, }; +static int mt7622_i2c1_0_funcs[] = { 0, 0, }; +static int mt7622_i2c1_1_pins[] = { 73, 74, }; +static int mt7622_i2c1_1_funcs[] = { 3, 3, }; +static int mt7622_i2c1_2_pins[] = { 87, 88, }; +static int mt7622_i2c1_2_funcs[] = { 0, 0, }; +static int mt7622_i2c2_0_pins[] = { 57, 58, }; +static int mt7622_i2c2_0_funcs[] = { 0, 0, }; +static int mt7622_i2c2_1_pins[] = { 75, 76, }; +static int mt7622_i2c2_1_funcs[] = { 3, 3, }; +static int mt7622_i2c2_2_pins[] = { 89, 90, }; +static int mt7622_i2c2_2_funcs[] = { 0, 0, }; + +/* I2S */ +static int mt7622_i2s_in_mclk_bclk_ws_pins[] = { 3, 4, 5, }; +static int mt7622_i2s_in_mclk_bclk_ws_funcs[] = { 3, 3, 0, }; +static int mt7622_i2s1_in_data_pins[] = { 1, }; +static int mt7622_i2s1_in_data_funcs[] = { 0, }; +static int mt7622_i2s2_in_data_pins[] = { 16, }; +static int mt7622_i2s2_in_data_funcs[] = { 0, }; +static int mt7622_i2s3_in_data_pins[] = { 17, }; +static int mt7622_i2s3_in_data_funcs[] = { 0, }; +static int mt7622_i2s4_in_data_pins[] = { 18, }; +static int mt7622_i2s4_in_data_funcs[] = { 0, }; +static int mt7622_i2s_out_mclk_bclk_ws_pins[] = { 3, 4, 5, }; +static int mt7622_i2s_out_mclk_bclk_ws_funcs[] = { 0, 0, 0, }; +static int mt7622_i2s1_out_data_pins[] = { 2, }; +static int mt7622_i2s1_out_data_funcs[] = { 0, }; +static int mt7622_i2s2_out_data_pins[] = { 19, }; +static int mt7622_i2s2_out_data_funcs[] = { 0, }; +static int mt7622_i2s3_out_data_pins[] = { 20, }; +static int mt7622_i2s3_out_data_funcs[] = { 0, }; +static int mt7622_i2s4_out_data_pins[] = { 21, }; +static int mt7622_i2s4_out_data_funcs[] = { 0, }; + +/* IR */ +static int mt7622_ir_0_tx_pins[] = { 16, }; +static int mt7622_ir_0_tx_funcs[] = { 4, }; +static int mt7622_ir_1_tx_pins[] = { 59, }; +static int mt7622_ir_1_tx_funcs[] = { 5, }; +static int mt7622_ir_2_tx_pins[] = { 99, }; +static int mt7622_ir_2_tx_funcs[] = { 3, }; +static int mt7622_ir_0_rx_pins[] = { 17, }; +static int mt7622_ir_0_rx_funcs[] = { 4, }; +static int mt7622_ir_1_rx_pins[] = { 60, }; +static int mt7622_ir_1_rx_funcs[] = { 5, }; +static int mt7622_ir_2_rx_pins[] = { 100, }; +static int mt7622_ir_2_rx_funcs[] = { 3, }; + +/* MDIO */ +static int mt7622_mdc_mdio_pins[] = { 23, 24, }; +static int mt7622_mdc_mdio_funcs[] = { 0, 0, }; + +/* PCIE */ +static int mt7622_pcie0_0_waken_pins[] = { 14, }; +static int mt7622_pcie0_0_waken_funcs[] = { 2, }; +static int mt7622_pcie0_0_clkreq_pins[] = { 15, }; +static int mt7622_pcie0_0_clkreq_funcs[] = { 2, }; +static int mt7622_pcie0_1_waken_pins[] = { 79, }; +static int mt7622_pcie0_1_waken_funcs[] = { 4, }; +static int mt7622_pcie0_1_clkreq_pins[] = { 80, }; +static int mt7622_pcie0_1_clkreq_funcs[] = { 4, }; +static int mt7622_pcie1_0_waken_pins[] = { 14, }; +static int mt7622_pcie1_0_waken_funcs[] = { 3, }; +static int mt7622_pcie1_0_clkreq_pins[] = { 15, }; +static int mt7622_pcie1_0_clkreq_funcs[] = { 3, }; + +static int mt7622_pcie0_pad_perst_pins[] = { 83, }; +static int mt7622_pcie0_pad_perst_funcs[] = { 0, }; +static int mt7622_pcie1_pad_perst_pins[] = { 84, }; +static int mt7622_pcie1_pad_perst_funcs[] = { 0, }; + +/* PMIC bus */ +static int mt7622_pmic_bus_pins[] = { 71, 72, }; +static int mt7622_pmic_bus_funcs[] = { 0, 0, }; + +/* Parallel NAND */ +static int mt7622_pnand_pins[] = { 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, }; +static int mt7622_pnand_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, }; + +/* PWM */ +static int mt7622_pwm_ch1_0_pins[] = { 51, }; +static int mt7622_pwm_ch1_0_funcs[] = { 3, }; +static int mt7622_pwm_ch1_1_pins[] = { 73, }; +static int mt7622_pwm_ch1_1_funcs[] = { 4, }; +static int mt7622_pwm_ch1_2_pins[] = { 95, }; +static int mt7622_pwm_ch1_2_funcs[] = { 0, }; +static int mt7622_pwm_ch2_0_pins[] = { 52, }; +static int mt7622_pwm_ch2_0_funcs[] = { 3, }; +static int mt7622_pwm_ch2_1_pins[] = { 74, }; +static int mt7622_pwm_ch2_1_funcs[] = { 4, }; +static int mt7622_pwm_ch2_2_pins[] = { 96, }; +static int mt7622_pwm_ch2_2_funcs[] = { 0, }; +static int mt7622_pwm_ch3_0_pins[] = { 53, }; +static int mt7622_pwm_ch3_0_funcs[] = { 3, }; +static int mt7622_pwm_ch3_1_pins[] = { 75, }; +static int mt7622_pwm_ch3_1_funcs[] = { 4, }; +static int mt7622_pwm_ch3_2_pins[] = { 97, }; +static int mt7622_pwm_ch3_2_funcs[] = { 0, }; +static int mt7622_pwm_ch4_0_pins[] = { 54, }; +static int mt7622_pwm_ch4_0_funcs[] = { 3, }; +static int mt7622_pwm_ch4_1_pins[] = { 67, }; +static int mt7622_pwm_ch4_1_funcs[] = { 3, }; +static int mt7622_pwm_ch4_2_pins[] = { 76, }; +static int mt7622_pwm_ch4_2_funcs[] = { 4, }; +static int mt7622_pwm_ch4_3_pins[] = { 98, }; +static int mt7622_pwm_ch4_3_funcs[] = { 0, }; +static int mt7622_pwm_ch5_0_pins[] = { 68, }; +static int mt7622_pwm_ch5_0_funcs[] = { 3, }; +static int mt7622_pwm_ch5_1_pins[] = { 77, }; +static int mt7622_pwm_ch5_1_funcs[] = { 4, }; +static int mt7622_pwm_ch5_2_pins[] = { 99, }; +static int mt7622_pwm_ch5_2_funcs[] = { 0, }; +static int mt7622_pwm_ch6_0_pins[] = { 69, }; +static int mt7622_pwm_ch6_0_funcs[] = { 3, }; +static int mt7622_pwm_ch6_1_pins[] = { 78, }; +static int mt7622_pwm_ch6_1_funcs[] = { 4, }; +static int mt7622_pwm_ch6_2_pins[] = { 81, }; +static int mt7622_pwm_ch6_2_funcs[] = { 4, }; +static int mt7622_pwm_ch6_3_pins[] = { 100, }; +static int mt7622_pwm_ch6_3_funcs[] = { 0, }; +static int mt7622_pwm_ch7_0_pins[] = { 70, }; +static int mt7622_pwm_ch7_0_funcs[] = { 3, }; +static int mt7622_pwm_ch7_1_pins[] = { 82, }; +static int mt7622_pwm_ch7_1_funcs[] = { 4, }; +static int mt7622_pwm_ch7_2_pins[] = { 101, }; +static int mt7622_pwm_ch7_2_funcs[] = { 0, }; + +/* SD */ +static int mt7622_sd_0_pins[] = { 16, 17, 18, 19, 20, 21, }; +static int mt7622_sd_0_funcs[] = { 2, 2, 2, 2, 2, 2, }; +static int mt7622_sd_1_pins[] = { 25, 26, 27, 28, 29, 30, }; +static int mt7622_sd_1_funcs[] = { 2, 2, 2, 2, 2, 2, }; + +/* Serial NAND */ +static int mt7622_snfi_pins[] = { 8, 9, 10, 11, 12, 13, }; +static int mt7622_snfi_funcs[] = { 2, 2, 2, 2, 2, 2, }; + +/* SPI NOR */ +static int mt7622_spi_pins[] = { 8, 9, 10, 11, 12, 13 }; +static int mt7622_spi_funcs[] = { 0, 0, 0, 0, 0, 0, }; + +/* SPIC */ +static int mt7622_spic0_0_pins[] = { 63, 64, 65, 66, }; +static int mt7622_spic0_0_funcs[] = { 4, 4, 4, 4, }; +static int mt7622_spic0_1_pins[] = { 79, 80, 81, 82, }; +static int mt7622_spic0_1_funcs[] = { 3, 3, 3, 3, }; +static int mt7622_spic1_0_pins[] = { 67, 68, 69, 70, }; +static int mt7622_spic1_0_funcs[] = { 4, 4, 4, 4, }; +static int mt7622_spic1_1_pins[] = { 73, 74, 75, 76, }; +static int mt7622_spic1_1_funcs[] = { 0, 0, 0, 0, }; +static int mt7622_spic2_0_pins[] = { 10, 11, 12, 13, }; +static int mt7622_spic2_0_funcs[] = { 0, 0, 0, 0, }; +static int mt7622_spic2_0_wp_hold_pins[] = { 8, 9, }; +static int mt7622_spic2_0_wp_hold_funcs[] = { 0, 0, }; + +/* TDM */ +static int mt7622_tdm_0_out_mclk_bclk_ws_pins[] = { 8, 9, 10, }; +static int mt7622_tdm_0_out_mclk_bclk_ws_funcs[] = { 3, 3, 3, }; +static int mt7622_tdm_0_in_mclk_bclk_ws_pins[] = { 11, 12, 13, }; +static int mt7622_tdm_0_in_mclk_bclk_ws_funcs[] = { 3, 3, 3, }; +static int mt7622_tdm_0_out_data_pins[] = { 20, }; +static int mt7622_tdm_0_out_data_funcs[] = { 3, }; +static int mt7622_tdm_0_in_data_pins[] = { 21, }; +static int mt7622_tdm_0_in_data_funcs[] = { 3, }; +static int mt7622_tdm_1_out_mclk_bclk_ws_pins[] = { 57, 58, 59, }; +static int mt7622_tdm_1_out_mclk_bclk_ws_funcs[] = { 3, 3, 3, }; +static int mt7622_tdm_1_in_mclk_bclk_ws_pins[] = { 60, 61, 62, }; +static int mt7622_tdm_1_in_mclk_bclk_ws_funcs[] = { 3, 3, 3, }; +static int mt7622_tdm_1_out_data_pins[] = { 55, }; +static int mt7622_tdm_1_out_data_funcs[] = { 3, }; +static int mt7622_tdm_1_in_data_pins[] = { 56, }; +static int mt7622_tdm_1_in_data_funcs[] = { 3, }; + +/* UART */ +static int mt7622_uart0_0_tx_rx_pins[] = { 6, 7, }; +static int mt7622_uart0_0_tx_rx_funcs[] = { 0, 0, }; +static int mt7622_uart1_0_tx_rx_pins[] = { 55, 56, }; +static int mt7622_uart1_0_tx_rx_funcs[] = { 2, 2, }; +static int mt7622_uart1_0_rts_cts_pins[] = { 57, 58, }; +static int mt7622_uart1_0_rts_cts_funcs[] = { 2, 2, }; +static int mt7622_uart1_1_tx_rx_pins[] = { 73, 74, }; +static int mt7622_uart1_1_tx_rx_funcs[] = { 2, 2, }; +static int mt7622_uart1_1_rts_cts_pins[] = { 75, 76, }; +static int mt7622_uart1_1_rts_cts_funcs[] = { 2, 2, }; +static int mt7622_uart2_0_tx_rx_pins[] = { 3, 4, }; +static int mt7622_uart2_0_tx_rx_funcs[] = { 2, 2, }; +static int mt7622_uart2_0_rts_cts_pins[] = { 1, 2, }; +static int mt7622_uart2_0_rts_cts_funcs[] = { 2, 2, }; +static int mt7622_uart2_1_tx_rx_pins[] = { 51, 52, }; +static int mt7622_uart2_1_tx_rx_funcs[] = { 0, 0, }; +static int mt7622_uart2_1_rts_cts_pins[] = { 53, 54, }; +static int mt7622_uart2_1_rts_cts_funcs[] = { 0, 0, }; +static int mt7622_uart2_2_tx_rx_pins[] = { 59, 60, }; +static int mt7622_uart2_2_tx_rx_funcs[] = { 4, 4, }; +static int mt7622_uart2_2_rts_cts_pins[] = { 61, 62, }; +static int mt7622_uart2_2_rts_cts_funcs[] = { 4, 4, }; +static int mt7622_uart2_3_tx_rx_pins[] = { 95, 96, }; +static int mt7622_uart2_3_tx_rx_funcs[] = { 3, 3, }; +static int mt7622_uart3_0_tx_rx_pins[] = { 57, 58, }; +static int mt7622_uart3_0_tx_rx_funcs[] = { 5, 5, }; +static int mt7622_uart3_1_tx_rx_pins[] = { 81, 82, }; +static int mt7622_uart3_1_tx_rx_funcs[] = { 0, 0, }; +static int mt7622_uart3_1_rts_cts_pins[] = { 79, 80, }; +static int mt7622_uart3_1_rts_cts_funcs[] = { 0, 0, }; +static int mt7622_uart4_0_tx_rx_pins[] = { 61, 62, }; +static int mt7622_uart4_0_tx_rx_funcs[] = { 5, 5, }; +static int mt7622_uart4_1_tx_rx_pins[] = { 91, 92, }; +static int mt7622_uart4_1_tx_rx_funcs[] = { 0, 0, }; +static int mt7622_uart4_1_rts_cts_pins[] = { 93, 94 }; +static int mt7622_uart4_1_rts_cts_funcs[] = { 0, 0, }; +static int mt7622_uart4_2_tx_rx_pins[] = { 97, 98, }; +static int mt7622_uart4_2_tx_rx_funcs[] = { 2, 2, }; +static int mt7622_uart4_2_rts_cts_pins[] = { 95, 96 }; +static int mt7622_uart4_2_rts_cts_funcs[] = { 2, 2, }; + +/* Watchdog */ +static int mt7622_watchdog_pins[] = { 78, }; +static int mt7622_watchdog_funcs[] = { 0, }; + +/* WLAN LED */ +static int mt7622_wled_pins[] = { 85, }; +static int mt7622_wled_funcs[] = { 0, }; + +static const struct group_desc mt7622_groups[] = { + PINCTRL_PIN_GROUP("emmc", mt7622_emmc), + PINCTRL_PIN_GROUP("emmc_rst", mt7622_emmc_rst), + PINCTRL_PIN_GROUP("ephy_leds", mt7622_ephy_leds), + PINCTRL_PIN_GROUP("ephy0_led", mt7622_ephy0_led), + PINCTRL_PIN_GROUP("ephy1_led", mt7622_ephy1_led), + PINCTRL_PIN_GROUP("ephy2_led", mt7622_ephy2_led), + PINCTRL_PIN_GROUP("ephy3_led", mt7622_ephy3_led), + PINCTRL_PIN_GROUP("ephy4_led", mt7622_ephy4_led), + PINCTRL_PIN_GROUP("esw", mt7622_esw), + PINCTRL_PIN_GROUP("esw_p0_p1", mt7622_esw_p0_p1), + PINCTRL_PIN_GROUP("esw_p2_p3_p4", mt7622_esw_p2_p3_p4), + PINCTRL_PIN_GROUP("rgmii_via_esw", mt7622_rgmii_via_esw), + PINCTRL_PIN_GROUP("rgmii_via_gmac1", mt7622_rgmii_via_gmac1), + PINCTRL_PIN_GROUP("rgmii_via_gmac2", mt7622_rgmii_via_gmac2), + PINCTRL_PIN_GROUP("i2c0", mt7622_i2c0), + PINCTRL_PIN_GROUP("i2c1_0", mt7622_i2c1_0), + PINCTRL_PIN_GROUP("i2c1_1", mt7622_i2c1_1), + PINCTRL_PIN_GROUP("i2c1_2", mt7622_i2c1_2), + PINCTRL_PIN_GROUP("i2c2_0", mt7622_i2c2_0), + PINCTRL_PIN_GROUP("i2c2_1", mt7622_i2c2_1), + PINCTRL_PIN_GROUP("i2c2_2", mt7622_i2c2_2), + PINCTRL_PIN_GROUP("i2s_out_mclk_bclk_ws", mt7622_i2s_out_mclk_bclk_ws), + PINCTRL_PIN_GROUP("i2s_in_mclk_bclk_ws", mt7622_i2s_in_mclk_bclk_ws), + PINCTRL_PIN_GROUP("i2s1_in_data", mt7622_i2s1_in_data), + PINCTRL_PIN_GROUP("i2s2_in_data", mt7622_i2s2_in_data), + PINCTRL_PIN_GROUP("i2s3_in_data", mt7622_i2s3_in_data), + PINCTRL_PIN_GROUP("i2s4_in_data", mt7622_i2s4_in_data), + PINCTRL_PIN_GROUP("i2s1_out_data", mt7622_i2s1_out_data), + PINCTRL_PIN_GROUP("i2s2_out_data", mt7622_i2s2_out_data), + PINCTRL_PIN_GROUP("i2s3_out_data", mt7622_i2s3_out_data), + PINCTRL_PIN_GROUP("i2s4_out_data", mt7622_i2s4_out_data), + PINCTRL_PIN_GROUP("ir_0_tx", mt7622_ir_0_tx), + PINCTRL_PIN_GROUP("ir_1_tx", mt7622_ir_1_tx), + PINCTRL_PIN_GROUP("ir_2_tx", mt7622_ir_2_tx), + PINCTRL_PIN_GROUP("ir_0_rx", mt7622_ir_0_rx), + PINCTRL_PIN_GROUP("ir_1_rx", mt7622_ir_1_rx), + PINCTRL_PIN_GROUP("ir_2_rx", mt7622_ir_2_rx), + PINCTRL_PIN_GROUP("mdc_mdio", mt7622_mdc_mdio), + PINCTRL_PIN_GROUP("pcie0_0_waken", mt7622_pcie0_0_waken), + PINCTRL_PIN_GROUP("pcie0_0_clkreq", mt7622_pcie0_0_clkreq), + PINCTRL_PIN_GROUP("pcie0_1_waken", mt7622_pcie0_1_waken), + PINCTRL_PIN_GROUP("pcie0_1_clkreq", mt7622_pcie0_1_clkreq), + PINCTRL_PIN_GROUP("pcie1_0_waken", mt7622_pcie1_0_waken), + PINCTRL_PIN_GROUP("pcie1_0_clkreq", mt7622_pcie1_0_clkreq), + PINCTRL_PIN_GROUP("pcie0_pad_perst", mt7622_pcie0_pad_perst), + PINCTRL_PIN_GROUP("pcie1_pad_perst", mt7622_pcie1_pad_perst), + PINCTRL_PIN_GROUP("par_nand", mt7622_pnand), + PINCTRL_PIN_GROUP("pmic_bus", mt7622_pmic_bus), + PINCTRL_PIN_GROUP("pwm_ch1_0", mt7622_pwm_ch1_0), + PINCTRL_PIN_GROUP("pwm_ch1_1", mt7622_pwm_ch1_1), + PINCTRL_PIN_GROUP("pwm_ch1_2", mt7622_pwm_ch1_2), + PINCTRL_PIN_GROUP("pwm_ch2_0", mt7622_pwm_ch2_0), + PINCTRL_PIN_GROUP("pwm_ch2_1", mt7622_pwm_ch2_1), + PINCTRL_PIN_GROUP("pwm_ch2_2", mt7622_pwm_ch2_2), + PINCTRL_PIN_GROUP("pwm_ch3_0", mt7622_pwm_ch3_0), + PINCTRL_PIN_GROUP("pwm_ch3_1", mt7622_pwm_ch3_1), + PINCTRL_PIN_GROUP("pwm_ch3_2", mt7622_pwm_ch3_2), + PINCTRL_PIN_GROUP("pwm_ch4_0", mt7622_pwm_ch4_0), + PINCTRL_PIN_GROUP("pwm_ch4_1", mt7622_pwm_ch4_1), + PINCTRL_PIN_GROUP("pwm_ch4_2", mt7622_pwm_ch4_2), + PINCTRL_PIN_GROUP("pwm_ch4_3", mt7622_pwm_ch4_3), + PINCTRL_PIN_GROUP("pwm_ch5_0", mt7622_pwm_ch5_0), + PINCTRL_PIN_GROUP("pwm_ch5_1", mt7622_pwm_ch5_1), + PINCTRL_PIN_GROUP("pwm_ch5_2", mt7622_pwm_ch5_2), + PINCTRL_PIN_GROUP("pwm_ch6_0", mt7622_pwm_ch6_0), + PINCTRL_PIN_GROUP("pwm_ch6_1", mt7622_pwm_ch6_1), + PINCTRL_PIN_GROUP("pwm_ch6_2", mt7622_pwm_ch6_2), + PINCTRL_PIN_GROUP("pwm_ch6_3", mt7622_pwm_ch6_3), + PINCTRL_PIN_GROUP("pwm_ch7_0", mt7622_pwm_ch7_0), + PINCTRL_PIN_GROUP("pwm_ch7_1", mt7622_pwm_ch7_1), + PINCTRL_PIN_GROUP("pwm_ch7_2", mt7622_pwm_ch7_2), + PINCTRL_PIN_GROUP("sd_0", mt7622_sd_0), + PINCTRL_PIN_GROUP("sd_1", mt7622_sd_1), + PINCTRL_PIN_GROUP("snfi", mt7622_snfi), + PINCTRL_PIN_GROUP("spi_nor", mt7622_spi), + PINCTRL_PIN_GROUP("spic0_0", mt7622_spic0_0), + PINCTRL_PIN_GROUP("spic0_1", mt7622_spic0_1), + PINCTRL_PIN_GROUP("spic1_0", mt7622_spic1_0), + PINCTRL_PIN_GROUP("spic1_1", mt7622_spic1_1), + PINCTRL_PIN_GROUP("spic2_0", mt7622_spic2_0), + PINCTRL_PIN_GROUP("spic2_0_wp_hold", mt7622_spic2_0_wp_hold), + PINCTRL_PIN_GROUP("tdm_0_out_mclk_bclk_ws", + mt7622_tdm_0_out_mclk_bclk_ws), + PINCTRL_PIN_GROUP("tdm_0_in_mclk_bclk_ws", + mt7622_tdm_0_in_mclk_bclk_ws), + PINCTRL_PIN_GROUP("tdm_0_out_data", mt7622_tdm_0_out_data), + PINCTRL_PIN_GROUP("tdm_0_in_data", mt7622_tdm_0_in_data), + PINCTRL_PIN_GROUP("tdm_1_out_mclk_bclk_ws", + mt7622_tdm_1_out_mclk_bclk_ws), + PINCTRL_PIN_GROUP("tdm_1_in_mclk_bclk_ws", + mt7622_tdm_1_in_mclk_bclk_ws), + PINCTRL_PIN_GROUP("tdm_1_out_data", mt7622_tdm_1_out_data), + PINCTRL_PIN_GROUP("tdm_1_in_data", mt7622_tdm_1_in_data), + PINCTRL_PIN_GROUP("uart0_0_tx_rx", mt7622_uart0_0_tx_rx), + PINCTRL_PIN_GROUP("uart1_0_tx_rx", mt7622_uart1_0_tx_rx), + PINCTRL_PIN_GROUP("uart1_0_rts_cts", mt7622_uart1_0_rts_cts), + PINCTRL_PIN_GROUP("uart1_1_tx_rx", mt7622_uart1_1_tx_rx), + PINCTRL_PIN_GROUP("uart1_1_rts_cts", mt7622_uart1_1_rts_cts), + PINCTRL_PIN_GROUP("uart2_0_tx_rx", mt7622_uart2_0_tx_rx), + PINCTRL_PIN_GROUP("uart2_0_rts_cts", mt7622_uart2_0_rts_cts), + PINCTRL_PIN_GROUP("uart2_1_tx_rx", mt7622_uart2_1_tx_rx), + PINCTRL_PIN_GROUP("uart2_1_rts_cts", mt7622_uart2_1_rts_cts), + PINCTRL_PIN_GROUP("uart2_2_tx_rx", mt7622_uart2_2_tx_rx), + PINCTRL_PIN_GROUP("uart2_2_rts_cts", mt7622_uart2_2_rts_cts), + PINCTRL_PIN_GROUP("uart2_3_tx_rx", mt7622_uart2_3_tx_rx), + PINCTRL_PIN_GROUP("uart3_0_tx_rx", mt7622_uart3_0_tx_rx), + PINCTRL_PIN_GROUP("uart3_1_tx_rx", mt7622_uart3_1_tx_rx), + PINCTRL_PIN_GROUP("uart3_1_rts_cts", mt7622_uart3_1_rts_cts), + PINCTRL_PIN_GROUP("uart4_0_tx_rx", mt7622_uart4_0_tx_rx), + PINCTRL_PIN_GROUP("uart4_1_tx_rx", mt7622_uart4_1_tx_rx), + PINCTRL_PIN_GROUP("uart4_1_rts_cts", mt7622_uart4_1_rts_cts), + PINCTRL_PIN_GROUP("uart4_2_tx_rx", mt7622_uart4_2_tx_rx), + PINCTRL_PIN_GROUP("uart4_2_rts_cts", mt7622_uart4_2_rts_cts), + PINCTRL_PIN_GROUP("watchdog", mt7622_watchdog), + PINCTRL_PIN_GROUP("wled", mt7622_wled), +}; + +/* Joint those groups owning the same capability in user point of view which + * allows that people tend to use through the device tree. + */ +static const char *mt7622_emmc_groups[] = { "emmc", "emmc_rst", }; +static const char *mt7622_ethernet_groups[] = { "esw", "esw_p0_p1", + "esw_p2_p3_p4", "mdc_mdio", + "rgmii_via_gmac1", + "rgmii_via_gmac2", + "rgmii_via_esw", }; +static const char *mt7622_i2c_groups[] = { "i2c0", "i2c1_0", "i2c1_1", + "i2c1_2", "i2c2_0", "i2c2_1", + "i2c2_2", }; +static const char *mt7622_i2s_groups[] = { "i2s_out_mclk_bclk_ws", + "i2s_in_mclk_bclk_ws", + "i2s1_in_data", "i2s2_in_data", + "i2s3_in_data", "i2s4_in_data", + "i2s1_out_data", "i2s2_out_data", + "i2s3_out_data", "i2s4_out_data", }; +static const char *mt7622_ir_groups[] = { "ir_0_tx", "ir_1_tx", "ir_2_tx", + "ir_0_rx", "ir_1_rx", "ir_2_rx"}; +static const char *mt7622_led_groups[] = { "ephy_leds", "ephy0_led", + "ephy1_led", "ephy2_led", + "ephy3_led", "ephy4_led", + "wled", }; +static const char *mt7622_flash_groups[] = { "par_nand", "snfi", "spi_nor"}; +static const char *mt7622_pcie_groups[] = { "pcie0_0_waken", "pcie0_0_clkreq", + "pcie0_1_waken", "pcie0_1_clkreq", + "pcie1_0_waken", "pcie1_0_clkreq", + "pcie0_pad_perst", + "pcie1_pad_perst", }; +static const char *mt7622_pmic_bus_groups[] = { "pmic_bus", }; +static const char *mt7622_pwm_groups[] = { "pwm_ch1_0", "pwm_ch1_1", + "pwm_ch1_2", "pwm_ch2_0", + "pwm_ch2_1", "pwm_ch2_2", + "pwm_ch3_0", "pwm_ch3_1", + "pwm_ch3_2", "pwm_ch4_0", + "pwm_ch4_1", "pwm_ch4_2", + "pwm_ch4_3", "pwm_ch5_0", + "pwm_ch5_1", "pwm_ch5_2", + "pwm_ch6_0", "pwm_ch6_1", + "pwm_ch6_2", "pwm_ch6_3", + "pwm_ch7_0", "pwm_ch7_1", + "pwm_ch7_2", }; +static const char *mt7622_sd_groups[] = { "sd_0", "sd_1", }; +static const char *mt7622_spic_groups[] = { "spic0_0", "spic0_1", "spic1_0", + "spic1_1", "spic2_0", + "spic2_0_wp_hold", }; +static const char *mt7622_tdm_groups[] = { "tdm_0_out_mclk_bclk_ws", + "tdm_0_in_mclk_bclk_ws", + "tdm_0_out_data", + "tdm_0_in_data", + "tdm_1_out_mclk_bclk_ws", + "tdm_1_in_mclk_bclk_ws", + "tdm_1_out_data", + "tdm_1_in_data", }; + +static const char *mt7622_uart_groups[] = { "uart0_0_tx_rx", + "uart1_0_tx_rx", "uart1_0_rts_cts", + "uart1_1_tx_rx", "uart1_1_rts_cts", + "uart2_0_tx_rx", "uart2_0_rts_cts", + "uart2_1_tx_rx", "uart2_1_rts_cts", + "uart2_2_tx_rx", "uart2_2_rts_cts", + "uart2_3_tx_rx", + "uart3_0_tx_rx", + "uart3_1_tx_rx", "uart3_1_rts_cts", + "uart4_0_tx_rx", + "uart4_1_tx_rx", "uart4_1_rts_cts", + "uart4_2_tx_rx", + "uart4_2_rts_cts",}; +static const char *mt7622_wdt_groups[] = { "watchdog", }; + +static const struct function_desc mt7622_functions[] = { + {"emmc", mt7622_emmc_groups, ARRAY_SIZE(mt7622_emmc_groups)}, + {"eth", mt7622_ethernet_groups, ARRAY_SIZE(mt7622_ethernet_groups)}, + {"i2c", mt7622_i2c_groups, ARRAY_SIZE(mt7622_i2c_groups)}, + {"i2s", mt7622_i2s_groups, ARRAY_SIZE(mt7622_i2s_groups)}, + {"ir", mt7622_ir_groups, ARRAY_SIZE(mt7622_ir_groups)}, + {"led", mt7622_led_groups, ARRAY_SIZE(mt7622_led_groups)}, + {"flash", mt7622_flash_groups, ARRAY_SIZE(mt7622_flash_groups)}, + {"pcie", mt7622_pcie_groups, ARRAY_SIZE(mt7622_pcie_groups)}, + {"pmic", mt7622_pmic_bus_groups, ARRAY_SIZE(mt7622_pmic_bus_groups)}, + {"pwm", mt7622_pwm_groups, ARRAY_SIZE(mt7622_pwm_groups)}, + {"sd", mt7622_sd_groups, ARRAY_SIZE(mt7622_sd_groups)}, + {"spi", mt7622_spic_groups, ARRAY_SIZE(mt7622_spic_groups)}, + {"tdm", mt7622_tdm_groups, ARRAY_SIZE(mt7622_tdm_groups)}, + {"uart", mt7622_uart_groups, ARRAY_SIZE(mt7622_uart_groups)}, + {"watchdog", mt7622_wdt_groups, ARRAY_SIZE(mt7622_wdt_groups)}, +}; + +static const struct pinconf_generic_params mtk_custom_bindings[] = { + {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, + {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item mtk_conf_items[] = { + PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), + PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), +}; +#endif + +static const struct mtk_pin_soc mt7622_data = { + .reg_cal = mt7622_reg_cals, + .pins = mt7622_pins, + .npins = ARRAY_SIZE(mt7622_pins), + .grps = mt7622_groups, + .ngrps = ARRAY_SIZE(mt7622_groups), + .funcs = mt7622_functions, + .nfuncs = ARRAY_SIZE(mt7622_functions), +}; + +static void mtk_w32(struct mtk_pinctrl *pctl, u32 reg, u32 val) +{ + writel_relaxed(val, pctl->base + reg); +} + +static u32 mtk_r32(struct mtk_pinctrl *pctl, u32 reg) +{ + return readl_relaxed(pctl->base + reg); +} + +static void mtk_rmw(struct mtk_pinctrl *pctl, u32 reg, u32 mask, u32 set) +{ + u32 val; + + val = mtk_r32(pctl, reg); + val &= ~mask; + val |= set; + mtk_w32(pctl, reg, val); +} + +static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw, int pin, + const struct mtk_pin_reg_calc *rc, + struct mtk_pin_field *pfd) +{ + const struct mtk_pin_field_calc *c, *e; + u32 bits; + + c = rc->range; + e = c + rc->nranges; + + while (c < e) { + if (pin >= c->s_pin && pin <= c->e_pin) + break; + c++; + } + + if (c >= e) { + dev_err(hw->dev, "Out of range for pin = %d\n", pin); + return -EINVAL; + } + + /* Caculated bits as the overall offset the pin is located at */ + bits = c->s_bit + (pin - c->s_pin) * (c->x_bits); + + /* Fill pfd from bits and 32-bit register applied is assumed */ + pfd->offset = c->s_addr + c->x_addrs * (bits / 32); + pfd->bitpos = bits % 32; + pfd->mask = (1 << c->x_bits) - 1; + + /* pfd->next is used for indicating that bit wrapping-around happens + * which requires the manipulation for bit 0 starting in the next + * register to form the complete field read/write. + */ + pfd->next = pfd->bitpos + c->x_bits - 1 > 31 ? c->x_addrs : 0; + + return 0; +} + +static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw, int pin, + int field, struct mtk_pin_field *pfd) +{ + const struct mtk_pin_reg_calc *rc; + + if (field < 0 || field >= PINCTRL_PIN_REG_MAX) { + dev_err(hw->dev, "Invalid Field %d\n", field); + return -EINVAL; + } + + if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) { + rc = &hw->soc->reg_cal[field]; + } else { + dev_err(hw->dev, "Undefined range for field %d\n", field); + return -EINVAL; + } + + return mtk_hw_pin_field_lookup(hw, pin, rc, pfd); +} + +static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l) +{ + *l = 32 - pf->bitpos; + *h = get_count_order(pf->mask) - *l; +} + +static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw, + struct mtk_pin_field *pf, int value) +{ + int nbits_l, nbits_h; + + mtk_hw_bits_part(pf, &nbits_h, &nbits_l); + + mtk_rmw(hw, pf->offset, pf->mask << pf->bitpos, + (value & pf->mask) << pf->bitpos); + + mtk_rmw(hw, pf->offset + pf->next, BIT(nbits_h) - 1, + (value & pf->mask) >> nbits_l); +} + +static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw, + struct mtk_pin_field *pf, int *value) +{ + int nbits_l, nbits_h, h, l; + + mtk_hw_bits_part(pf, &nbits_h, &nbits_l); + + l = (mtk_r32(hw, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1); + h = (mtk_r32(hw, pf->offset + pf->next)) & (BIT(nbits_h) - 1); + + *value = (h << nbits_l) | l; +} + +static int mtk_hw_set_value(struct mtk_pinctrl *hw, int pin, int field, + int value) +{ + struct mtk_pin_field pf; + int err; + + err = mtk_hw_pin_field_get(hw, pin, field, &pf); + if (err) + return err; + + if (!pf.next) + mtk_rmw(hw, pf.offset, pf.mask << pf.bitpos, + (value & pf.mask) << pf.bitpos); + else + mtk_hw_write_cross_field(hw, &pf, value); + + return 0; +} + +static int mtk_hw_get_value(struct mtk_pinctrl *hw, int pin, int field, + int *value) +{ + struct mtk_pin_field pf; + int err; + + err = mtk_hw_pin_field_get(hw, pin, field, &pf); + if (err) + return err; + + if (!pf.next) + *value = (mtk_r32(hw, pf.offset) >> pf.bitpos) & pf.mask; + else + mtk_hw_read_cross_field(hw, &pf, value); + + return 0; +} + +static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned int group) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + struct function_desc *func; + struct group_desc *grp; + int i; + + func = pinmux_generic_get_function(pctldev, selector); + if (!func) + return -EINVAL; + + grp = pinctrl_generic_get_group(pctldev, group); + if (!grp) + return -EINVAL; + + dev_dbg(pctldev->dev, "enable function %s group %s\n", + func->name, grp->name); + + for (i = 0; i < grp->num_pins; i++) { + int *pin_modes = grp->data; + + mtk_hw_set_value(hw, grp->pins[i], PINCTRL_PIN_REG_MODE, + pin_modes[i]); + } + + return 0; +} + +static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + + return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_MODE, MTK_GPIO_MODE); +} + +static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin, bool input) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + + /* hardware would take 0 as input direction */ + return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, !input); +} + +static int mtk_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + u32 param = pinconf_to_config_param(*config); + int val, val2, err, reg, ret = 1; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PU, &val); + if (err) + return err; + + err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PD, &val2); + if (err) + return err; + + if (val || val2) + return -EINVAL; + + break; + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_SLEW_RATE: + reg = (param == PIN_CONFIG_BIAS_PULL_UP) ? + PINCTRL_PIN_REG_PU : + (param == PIN_CONFIG_BIAS_PULL_DOWN) ? + PINCTRL_PIN_REG_PD : PINCTRL_PIN_REG_SR; + + err = mtk_hw_get_value(hw, pin, reg, &val); + if (err) + return err; + + if (!val) + return -EINVAL; + + break; + case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_OUTPUT_ENABLE: + err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val); + if (err) + return -EINVAL; + + /* HW takes input mode as zero; output mode as non-zero */ + if ((val && param == PIN_CONFIG_INPUT_ENABLE) || + (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) + return -EINVAL; + + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val); + if (err) + return err; + + err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_SMT, &val2); + if (err) + return err; + + if (val || !val2) + return -EINVAL; + + break; + case PIN_CONFIG_DRIVE_STRENGTH: + err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E4, &val); + if (err) + return -EINVAL; + + err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E8, &val2); + if (err) + return -EINVAL; + + /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1) + * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1) + */ + ret = ((val2 << 1) + val + 1) * 4; + + break; + case MTK_PIN_CONFIG_TDSEL: + case MTK_PIN_CONFIG_RDSEL: + reg = (param == MTK_PIN_CONFIG_TDSEL) ? + PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; + + err = mtk_hw_get_value(hw, pin, reg, &val); + if (err) + return -EINVAL; + + ret = val; + + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, ret); + + return 0; +} + +static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + u32 reg, param, arg; + int cfg, err = 0; + + for (cfg = 0; cfg < num_configs; cfg++) { + param = pinconf_to_config_param(configs[cfg]); + arg = pinconf_to_config_argument(configs[cfg]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 : + (param == PIN_CONFIG_BIAS_PULL_UP) ? 1 : 2; + + err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PU, + arg & 1); + if (err) + goto err; + + err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PD, + !!(arg & 2)); + if (err) + goto err; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT, + MTK_DISABLE); + if (err) + goto err; + case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_SLEW_RATE: + reg = (param == PIN_CONFIG_SLEW_RATE) ? + PINCTRL_PIN_REG_SR : PINCTRL_PIN_REG_DIR; + + arg = (param == PIN_CONFIG_INPUT_ENABLE) ? 0 : + (param == PIN_CONFIG_OUTPUT_ENABLE) ? 1 : arg; + err = mtk_hw_set_value(hw, pin, reg, arg); + if (err) + goto err; + + break; + case PIN_CONFIG_OUTPUT: + err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, + MTK_OUTPUT); + if (err) + goto err; + + err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DO, + arg); + if (err) + goto err; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + /* arg = 1: Input mode & SMT enable ; + * arg = 0: Output mode & SMT disable + */ + arg = arg ? 2 : 1; + err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, + arg & 1); + if (err) + goto err; + + err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT, + !!(arg & 2)); + if (err) + goto err; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + /* 4mA when (e8, e4) = (0, 0); + * 8mA when (e8, e4) = (0, 1); + * 12mA when (e8, e4) = (1, 0); + * 16mA when (e8, e4) = (1, 1) + */ + if (!(arg % 4) && (arg >= 4 && arg <= 16)) { + arg = arg / 4 - 1; + err = mtk_hw_set_value(hw, pin, + PINCTRL_PIN_REG_E4, + arg & 0x1); + if (err) + goto err; + + err = mtk_hw_set_value(hw, pin, + PINCTRL_PIN_REG_E8, + (arg & 0x2) >> 1); + if (err) + goto err; + } else { + err = -ENOTSUPP; + } + break; + case MTK_PIN_CONFIG_TDSEL: + case MTK_PIN_CONFIG_RDSEL: + reg = (param == MTK_PIN_CONFIG_TDSEL) ? + PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; + + err = mtk_hw_set_value(hw, pin, reg, arg); + if (err) + goto err; + break; + default: + err = -ENOTSUPP; + } + } +err: + return err; +} + +static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *config) +{ + const unsigned int *pins; + unsigned int i, npins, old = 0; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + for (i = 0; i < npins; i++) { + if (mtk_pinconf_get(pctldev, pins[i], config)) + return -ENOTSUPP; + + /* configs do not match between two pins */ + if (i && old != *config) + return -ENOTSUPP; + + old = *config; + } + + return 0; +} + +static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *configs, + unsigned int num_configs) +{ + const unsigned int *pins; + unsigned int i, npins; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + for (i = 0; i < npins; i++) { + ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinctrl_ops mtk_pctlops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static const struct pinmux_ops mtk_pmxops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = mtk_pinmux_set_mux, + .gpio_request_enable = mtk_pinmux_gpio_request_enable, + .gpio_set_direction = mtk_pinmux_gpio_set_direction, + .strict = true, +}; + +static const struct pinconf_ops mtk_confops = { + .is_generic = true, + .pin_config_get = mtk_pinconf_get, + .pin_config_set = mtk_pinconf_set, + .pin_config_group_get = mtk_pinconf_group_get, + .pin_config_group_set = mtk_pinconf_group_set, + .pin_config_config_dbg_show = pinconf_generic_dump_config, +}; + +static struct pinctrl_desc mtk_desc = { + .name = PINCTRL_PINCTRL_DEV, + .pctlops = &mtk_pctlops, + .pmxops = &mtk_pmxops, + .confops = &mtk_confops, + .owner = THIS_MODULE, +}; + +static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) +{ + struct mtk_pinctrl *hw = dev_get_drvdata(chip->parent); + int value; + + mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value); + + return !!value; +} + +static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) +{ + struct mtk_pinctrl *hw = dev_get_drvdata(chip->parent); + + mtk_hw_set_value(hw, gpio, PINCTRL_PIN_REG_DO, !!value); +} + +static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) +{ + return pinctrl_gpio_direction_input(chip->base + gpio); +} + +static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, + int value) +{ + mtk_gpio_set(chip, gpio, value); + + return pinctrl_gpio_direction_output(chip->base + gpio); +} + +static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np) +{ + struct gpio_chip *chip = &hw->chip; + int ret; + + chip->label = PINCTRL_PINCTRL_DEV; + chip->parent = hw->dev; + chip->request = gpiochip_generic_request; + chip->free = gpiochip_generic_free; + chip->direction_input = mtk_gpio_direction_input; + chip->direction_output = mtk_gpio_direction_output; + chip->get = mtk_gpio_get; + chip->set = mtk_gpio_set; + chip->base = -1; + chip->ngpio = hw->soc->npins; + chip->of_node = np; + chip->of_gpio_n_cells = 2; + + ret = gpiochip_add_data(chip, hw); + if (ret < 0) + return ret; + + ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0, + chip->ngpio); + if (ret < 0) { + gpiochip_remove(chip); + return ret; + } + + return 0; +} + +static int mtk_build_groups(struct mtk_pinctrl *hw) +{ + int err, i; + + for (i = 0; i < hw->soc->ngrps; i++) { + const struct group_desc *group = hw->soc->grps + i; + + err = pinctrl_generic_add_group(hw->pctrl, group->name, + group->pins, group->num_pins, + group->data); + if (err) { + dev_err(hw->dev, "Failed to register group %s\n", + group->name); + return err; + } + } + + return 0; +} + +static int mtk_build_functions(struct mtk_pinctrl *hw) +{ + int i, err; + + for (i = 0; i < hw->soc->nfuncs ; i++) { + const struct function_desc *func = hw->soc->funcs + i; + + err = pinmux_generic_add_function(hw->pctrl, func->name, + func->group_names, + func->num_group_names, + func->data); + if (err) { + dev_err(hw->dev, "Failed to register function %s\n", + func->name); + return err; + } + } + + return 0; +} + +static const struct of_device_id mtk_pinctrl_of_match[] = { + { .compatible = "mediatek,mt7622-pinctrl", .data = &mt7622_data}, + { } +}; + +static int mtk_pinctrl_probe(struct platform_device *pdev) +{ + struct resource *res; + struct mtk_pinctrl *hw; + const struct of_device_id *of_id = + of_match_device(mtk_pinctrl_of_match, &pdev->dev); + int err; + + hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return -ENOMEM; + + hw->soc = of_id->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing IO resource\n"); + return -ENXIO; + } + + hw->dev = &pdev->dev; + hw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->base)) + return PTR_ERR(hw->base); + + /* Setup pins descriptions per SoC types */ + mtk_desc.pins = hw->soc->pins; + mtk_desc.npins = hw->soc->npins; + mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); + mtk_desc.custom_params = mtk_custom_bindings; +#ifdef CONFIG_DEBUG_FS + mtk_desc.custom_conf_items = mtk_conf_items; +#endif + + hw->pctrl = devm_pinctrl_register(&pdev->dev, &mtk_desc, hw); + if (IS_ERR(hw->pctrl)) + return PTR_ERR(hw->pctrl); + + /* Setup groups descriptions per SoC types */ + err = mtk_build_groups(hw); + if (err) { + dev_err(&pdev->dev, "Failed to build groups\n"); + return 0; + } + + /* Setup functions descriptions per SoC types */ + err = mtk_build_functions(hw); + if (err) { + dev_err(&pdev->dev, "Failed to build functions\n"); + return err; + } + + err = mtk_build_gpiochip(hw, pdev->dev.of_node); + if (err) { + dev_err(&pdev->dev, "Failed to add gpio_chip\n"); + return err; + } + + platform_set_drvdata(pdev, hw); + + return 0; +} + +static struct platform_driver mtk_pinctrl_driver = { + .driver = { + .name = "mtk-pinctrl", + .of_match_table = mtk_pinctrl_of_match, + }, + .probe = mtk_pinctrl_probe, +}; + +static int __init mtk_pinctrl_init(void) +{ + return platform_driver_register(&mtk_pinctrl_driver); +} +arch_initcall(mtk_pinctrl_init); -- cgit From 5c9d8c4f6b8168738a26bcf288516cc3a0886810 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 12 Dec 2017 09:43:43 -0800 Subject: pinctrl: rockchip: enable clock when reading pin direction register We generally leave the GPIO clock disabled, unless an interrupt is requested or we're accessing IO registers. We forgot to do this for the ->get_direction() callback, which means we can sometimes [1] get incorrect results [2] from, e.g., /sys/kernel/debug/gpio. Enable the clock, so we get the right results! [1] Sometimes, because many systems have 1 or mor interrupt requested on each GPIO bank, so they always leave their clock on. [2] Incorrect, meaning the register returns 0, and so we interpret that as "input". Signed-off-by: Brian Norris Reviewed-by: Heiko Stuebner Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 2ba17548ad5b..073de6a9ed34 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -2014,8 +2014,16 @@ static int rockchip_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct rockchip_pin_bank *bank = gpiochip_get_data(chip); u32 data; + int ret; + ret = clk_enable(bank->clk); + if (ret < 0) { + dev_err(bank->drvdata->dev, + "failed to enable clock for bank %s\n", bank->name); + return ret; + } data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); + clk_disable(bank->clk); return !(data & BIT(offset)); } -- cgit From a049815229b6fcf0dd927630cbf5c127f5fb2a82 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 13 Dec 2017 09:55:03 +0100 Subject: pinctrl: axp209: dereference pointer after it's been set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The number of GPIOs is gotten from a field within the structure referenced in the of_device.data but it was actually read before it was retrieved, thus it was dereferencing a null pointer. Set the number of GPIOs after retrieving of_device.data. Fixes: e1190083b89b ("pinctrl: axp209: add support for AXP813 GPIOs") Signed-off-by: Quentin Schulz Reported-by: Mylène Josserand Tested-by: Mylène Josserand Acked-by: Chen-Yu Tsai Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-axp209.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index 22d3bb0bf927..510a2821e910 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -413,9 +413,11 @@ static int axp20x_pctl_probe(struct platform_device *pdev) pctl->chip.set = axp20x_gpio_set; pctl->chip.direction_input = axp20x_gpio_input; pctl->chip.direction_output = axp20x_gpio_output; - pctl->chip.ngpio = pctl->desc->npins; pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); + + pctl->chip.ngpio = pctl->desc->npins; + pctl->regmap = axp20x->regmap; pctl->dev = &pdev->dev; -- cgit From 971f1b38f960f8093228c07d92f19885fc719455 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 14 Dec 2017 10:43:35 +0100 Subject: pinctrl: axp209: add missing Kconfig dependencies This fixes some compilation issues. GENERIC_PINCONF and OF at least for pinconf_generic_dt_*, PINMUX at least for pinmux_ops and GPIOLIB for at least gpio_chip. Fixes: 23f75d7dfa92 ("pinctrl: axp209: add pinctrl features") Reported-by: Randy Dunlap Signed-off-by: Quentin Schulz Acked-by: Randy Dunlap Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ce126955212c..1dd445116432 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -66,6 +66,10 @@ config PINCTRL_AS3722 config PINCTRL_AXP209 tristate "X-Powers AXP209 PMIC pinctrl and GPIO Support" depends on MFD_AXP20X + depends on OF + select PINMUX + select GENERIC_PINCONF + select GPIOLIB help AXP PMICs provides multiple GPIOs that can be muxed for different functions. This driver bundles a pinctrl driver to select the function -- cgit From c2584927b7c89b0f28f5776e65a26944a07dffd3 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 14 Dec 2017 08:51:15 -0800 Subject: pinctrl: single: Remove invalid message Pinctrl single should just show how many pins were found, the physical address is already in the dev information. So let's remove the wrong information that claims to show the physical address but really prints a virtual address that is now hashed. Signed-off-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-single.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index e6cd8de793e2..6f95e6a74e72 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1774,8 +1774,7 @@ static int pcs_probe(struct platform_device *pdev) dev_warn(pcs->dev, "initialized with no interrupts\n"); } - dev_info(pcs->dev, "%i pins at pa %p size %u\n", - pcs->desc.npins, pcs->base, pcs->size); + dev_info(pcs->dev, "%i pins, size %u\n", pcs->desc.npins, pcs->size); return pinctrl_enable(pcs->pctl); -- cgit From bca50ce005731251edb663fc3519fa4a21ce309c Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 19 Dec 2017 22:30:36 +0100 Subject: pinctrl: mvebu: Delete an error message for a failed memory allocation in mvebu_pinctrl_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/mvebu/pinctrl-mvebu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index 163d4614b0f8..9e05cfaf75f0 100644 --- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -636,10 +636,9 @@ int mvebu_pinctrl_probe(struct platform_device *pdev) */ size = pctl->num_groups * sizeof(*pctl->groups) + noname * 8; p = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!p) { - dev_err(&pdev->dev, "failed to alloc group data\n"); + if (!p) return -ENOMEM; - } + pctl->groups = p; noname_buf = p + pctl->num_groups * sizeof(*pctl->groups); -- cgit From 297e5b2b7a8398b4b850d6bdb63f3a3544670b9e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 20 Dec 2017 22:59:22 +0100 Subject: pinctrl: sh-pfc: r8a7795: Add SATA pins, groups, and functions Tested with a Salvator-XS and H3 ES2.0. Signed-off-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/sh-pfc/pfc-r8a7795.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index 7eddd0f2f847..18aeee592fdc 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -3227,6 +3227,22 @@ static const unsigned int pwm6_b_mux[] = { PWM6_B_MARK, }; +/* - SATA --------------------------------------------------------------------*/ +static const unsigned int sata0_devslp_a_pins[] = { + /* DEVSLP */ + RCAR_GP_PIN(6, 16), +}; +static const unsigned int sata0_devslp_a_mux[] = { + SATA_DEVSLP_A_MARK, +}; +static const unsigned int sata0_devslp_b_pins[] = { + /* DEVSLP */ + RCAR_GP_PIN(4, 6), +}; +static const unsigned int sata0_devslp_b_mux[] = { + SATA_DEVSLP_B_MARK, +}; + /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_pins[] = { /* RX, TX */ @@ -4092,6 +4108,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(pwm5_b), SH_PFC_PIN_GROUP(pwm6_a), SH_PFC_PIN_GROUP(pwm6_b), + SH_PFC_PIN_GROUP(sata0_devslp_a), + SH_PFC_PIN_GROUP(sata0_devslp_b), SH_PFC_PIN_GROUP(scif0_data), SH_PFC_PIN_GROUP(scif0_clk), SH_PFC_PIN_GROUP(scif0_ctrl), @@ -4500,6 +4518,11 @@ static const char * const pwm6_groups[] = { "pwm6_b", }; +static const char * const sata0_groups[] = { + "sata0_devslp_a", + "sata0_devslp_b", +}; + static const char * const scif0_groups[] = { "scif0_data", "scif0_clk", @@ -4669,6 +4692,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(pwm4), SH_PFC_FUNCTION(pwm5), SH_PFC_FUNCTION(pwm6), + SH_PFC_FUNCTION(sata0), SH_PFC_FUNCTION(scif0), SH_PFC_FUNCTION(scif1), SH_PFC_FUNCTION(scif2), -- cgit From 8931dc0804a243bbe9bc45f72bf71307854177e5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 20 Dec 2017 10:12:56 +0100 Subject: pinctrl/nomadik/abx500: Delete an error message for a failed memory allocation in abx500_gpio_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index b32c0d602024..feb030d1ea63 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -1157,11 +1157,8 @@ static int abx500_gpio_probe(struct platform_device *pdev) pct = devm_kzalloc(&pdev->dev, sizeof(struct abx500_pinctrl), GFP_KERNEL); - if (pct == NULL) { - dev_err(&pdev->dev, - "failed to allocate memory for pct\n"); + if (!pct) return -ENOMEM; - } pct->dev = &pdev->dev; pct->parent = dev_get_drvdata(pdev->dev.parent); -- cgit From cb1a42d5fac615df0656622ea0f28cec1398fd39 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 20 Dec 2017 10:22:53 +0100 Subject: pinctrl/nomadik/abx500: Improve a size determination in abx500_gpio_probe() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index feb030d1ea63..7d00a5d864f5 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -1155,8 +1155,7 @@ static int abx500_gpio_probe(struct platform_device *pdev) return -ENODEV; } - pct = devm_kzalloc(&pdev->dev, sizeof(struct abx500_pinctrl), - GFP_KERNEL); + pct = devm_kzalloc(&pdev->dev, sizeof(*pct), GFP_KERNEL); if (!pct) return -ENOMEM; -- cgit From 419517f15df3a5ebaf5d05acfbc74be3f8377641 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 20 Dec 2017 12:32:10 +0100 Subject: pinctrl: adi2: Delete an error message for a failed memory allocation in two functions Omit an extra message for a memory allocation failure in these functions. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-adi2.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index 56aa181084ac..aefaf5855089 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -830,10 +830,8 @@ static int adi_gpio_pint_probe(struct platform_device *pdev) struct gpio_pint *pint; pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL); - if (!pint) { - dev_err(dev, "Memory alloc failed\n"); + if (!pint) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pint->base = devm_ioremap_resource(dev, res); @@ -946,10 +944,8 @@ static int adi_gpio_probe(struct platform_device *pdev) return -EINVAL; port = devm_kzalloc(dev, sizeof(struct gpio_port), GFP_KERNEL); - if (!port) { - dev_err(dev, "Memory alloc failed\n"); + if (!port) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->base = devm_ioremap_resource(dev, res); -- cgit From ce8b8d70d4d8d6351be44a467a2b61096dfc7a47 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 20 Dec 2017 12:38:53 +0100 Subject: pinctrl: adi2: Improve a size determination in two functions Replace the specification of data structures by variable references as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-adi2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index aefaf5855089..094a451db2a2 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -827,9 +827,8 @@ static int adi_gpio_pint_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; - struct gpio_pint *pint; + struct gpio_pint *pint = devm_kzalloc(dev, sizeof(*pint), GFP_KERNEL); - pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL); if (!pint) return -ENOMEM; @@ -943,7 +942,7 @@ static int adi_gpio_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - port = devm_kzalloc(dev, sizeof(struct gpio_port), GFP_KERNEL); + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; -- cgit From 203f4b0651cd4153bb3530ae4af63b5190cbe939 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 27 Dec 2017 22:04:22 +0100 Subject: pinctrl: msm: Delete an error message for a failed memory allocation in msm_pinctrl_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-msm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 7a960590ecaa..495432f3341b 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -898,10 +898,9 @@ int msm_pinctrl_probe(struct platform_device *pdev, int ret; pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); - if (!pctrl) { - dev_err(&pdev->dev, "Can't allocate msm_pinctrl\n"); + if (!pctrl) return -ENOMEM; - } + pctrl->dev = &pdev->dev; pctrl->soc = soc_data; pctrl->chip = msm_gpio_template; -- cgit From e210a0a9489d01223ef02627f95449ba73dde3a0 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 28 Dec 2017 21:20:09 +0800 Subject: pinctrl: sunxi: fix a typo when merging A20 support to A10 driver When merging A20 pinctrl support to A10 pinctrl driver, the I2C function of PI3 is wrongly written as "i2c3" (it should be "i2c4"). Fix this typo. Fixes: cad4e209c102 ("pinctrl: sunxi: add support of R40 to A10 pinctrl driver") Reported-by: Mark Kettenis Signed-off-by: Icenowy Zheng Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c index 295e48fc94bc..0c7c361ebac5 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c @@ -1167,7 +1167,7 @@ static const struct sunxi_desc_pin sun4i_a10_pins[] = { SUNXI_FUNCTION(0x0, "gpio_in"), SUNXI_FUNCTION(0x1, "gpio_out"), SUNXI_FUNCTION(0x2, "pwm"), /* PWM1 */ - SUNXI_FUNCTION_VARIANT(0x3, "i2c3", /* SDA */ + SUNXI_FUNCTION_VARIANT(0x3, "i2c4", /* SDA */ PINCTRL_SUN7I_A20 | PINCTRL_SUN8I_R40)), SUNXI_PIN(SUNXI_PINCTRL_PIN(I, 4), -- cgit From 8f6d6016898615012ec92957fba65a23b7ae16c9 Mon Sep 17 00:00:00 2001 From: Adrian Fiergolski Date: Mon, 25 Dec 2017 22:26:46 +0100 Subject: i2c: mux: pca954x: add support for NXP PCA984x family This patch extends the current i2c-mux-pca954x driver and adds support for a newer PCA984x family of the I2C switches and multiplexers from NXP. Signed-off-by: Adrian Fiergolski Reviewed-by: Rob Herring Signed-off-by: Peter Rosin --- drivers/i2c/muxes/Kconfig | 6 +++--- drivers/i2c/muxes/i2c-mux-pca954x.c | 38 +++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 0f5c8fc36625..52a4a922e7e6 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -64,11 +64,11 @@ config I2C_MUX_PCA9541 will be called i2c-mux-pca9541. config I2C_MUX_PCA954x - tristate "Philips PCA954x I2C Mux/switches" + tristate "NXP PCA954x and PCA984x I2C Mux/switches" depends on GPIOLIB || COMPILE_TEST help - If you say yes here you get support for the Philips PCA954x - I2C mux/switch devices. + If you say yes here you get support for the NXP PCA954x + and PCA984x I2C mux/switch devices. This driver can also be built as a module. If so, the module will be called i2c-mux-pca954x. diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 2ca068d8b92d..fbb84c7ef282 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -4,11 +4,11 @@ * Copyright (c) 2008-2009 Rodolfo Giometti * Copyright (c) 2008-2009 Eurotech S.p.A. * - * This module supports the PCA954x series of I2C multiplexer/switch chips - * made by Philips Semiconductors. + * This module supports the PCA954x and PCA954x series of I2C multiplexer/switch + * chips made by NXP Semiconductors. * This includes the: - * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547 - * and PCA9548. + * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547, + * PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849. * * These chips are all controlled via the I2C bus itself, and all have a * single 8-bit register. The upstream "parent" bus fans out to two, @@ -63,6 +63,10 @@ enum pca_type { pca_9546, pca_9547, pca_9548, + pca_9846, + pca_9847, + pca_9848, + pca_9849, }; struct chip_desc { @@ -129,6 +133,24 @@ static const struct chip_desc chips[] = { .nchans = 8, .muxtype = pca954x_isswi, }, + [pca_9846] = { + .nchans = 4, + .muxtype = pca954x_isswi, + }, + [pca_9847] = { + .nchans = 8, + .enable = 0x8, + .muxtype = pca954x_ismux, + }, + [pca_9848] = { + .nchans = 8, + .muxtype = pca954x_isswi, + }, + [pca_9849] = { + .nchans = 4, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, }; static const struct i2c_device_id pca954x_id[] = { @@ -140,6 +162,10 @@ static const struct i2c_device_id pca954x_id[] = { { "pca9546", pca_9546 }, { "pca9547", pca_9547 }, { "pca9548", pca_9548 }, + { "pca9846", pca_9846 }, + { "pca9847", pca_9847 }, + { "pca9848", pca_9848 }, + { "pca9849", pca_9849 }, { } }; MODULE_DEVICE_TABLE(i2c, pca954x_id); @@ -154,6 +180,10 @@ static const struct of_device_id pca954x_of_match[] = { { .compatible = "nxp,pca9546", .data = &chips[pca_9546] }, { .compatible = "nxp,pca9547", .data = &chips[pca_9547] }, { .compatible = "nxp,pca9548", .data = &chips[pca_9548] }, + { .compatible = "nxp,pca9846", .data = &chips[pca_9846] }, + { .compatible = "nxp,pca9847", .data = &chips[pca_9847] }, + { .compatible = "nxp,pca9848", .data = &chips[pca_9848] }, + { .compatible = "nxp,pca9849", .data = &chips[pca_9849] }, {} }; MODULE_DEVICE_TABLE(of, pca954x_of_match); -- cgit From ac5b85de17cb96445c51bd1a1c53c3f675582f26 Mon Sep 17 00:00:00 2001 From: Tomasz Bachorski Date: Mon, 18 Dec 2017 17:18:39 +0100 Subject: i2c: mux: reg: don't log an error for probe deferral It's possible that i2c_mux_reg_probe_dt() could return -EPROBE_DEFER. In that case, driver will request a probe deferral and an error suggesting device tree parsing problem will be reported. This is a pretty confusing information. Let's change the error handling, so driver will be able to request probe deferral without logging not related errors. Signed-off-by: Tomasz Bachorski Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-reg.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index f6c9c3dc6cad..c948e5a4cb04 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -177,6 +177,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) sizeof(mux->data)); } else { ret = i2c_mux_reg_probe_dt(mux, pdev); + if (ret == -EPROBE_DEFER) + return ret; + if (ret < 0) { dev_err(&pdev->dev, "Error parsing device tree"); return ret; -- cgit From e53537653791b4aaa9ec88a9eb5fd187d44ff6ac Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 20 Dec 2017 13:17:49 +0100 Subject: i2c/ARM: davinci: Deep refactoring of I2C recovery Alter the DaVinci GPIO recovery fetch to use descriptors all the way down into the board files. Signed-off-by: Linus Walleij Acked-by: Sekhar Nori Tested-by: Sekhar Nori Acked-by: Arnd Bergmann Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-davinci.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 2afb12a89eb3..cb24a3ffdfa2 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -869,19 +869,20 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (dev->pdata->has_pfunc) adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; - else if (dev->pdata->scl_pin) { + else if (dev->pdata->gpio_recovery) { rinfo = &davinci_i2c_gpio_recovery_info; adap->bus_recovery_info = rinfo; - r = gpio_request_one(dev->pdata->scl_pin, GPIOF_OPEN_DRAIN | - GPIOF_OUT_INIT_HIGH, "i2c-scl"); - if (r) + rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", + GPIOD_OUT_HIGH_OPEN_DRAIN); + if (IS_ERR(rinfo->scl_gpiod)) { + r = PTR_ERR(rinfo->scl_gpiod); goto err_unuse_clocks; - rinfo->scl_gpiod = gpio_to_desc(dev->pdata->scl_pin); - - r = gpio_request_one(dev->pdata->sda_pin, GPIOF_IN, "i2c-sda"); - if (r) + } + rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); + if (IS_ERR(rinfo->sda_gpiod)) { + r = PTR_ERR(rinfo->sda_gpiod); goto err_unuse_clocks; - rinfo->sda_gpiod = gpio_to_desc(dev->pdata->scl_pin); + } } adap->nr = pdev->id; -- cgit From 3e5f06bed72fe72166a6778f630241a893f67799 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 4 Dec 2017 09:16:18 +0100 Subject: i2c: algo-bit: init the bus to a known state Ensure the bus is free when we register the adapter. Before the SCL/SDA wires were in an unknown state. It used to work because sending a byte has a retry mechanism which was triggered if the bus was initially in a non-free state. But the graceful way to do it is to initialize correctly. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/algos/i2c-algo-bit.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 1147bddb8b2c..3df0efd69ae3 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -649,6 +649,11 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, if (bit_adap->getscl == NULL) adap->quirks = &i2c_bit_quirk_no_clk_stretch; + /* Bring bus to a known state. Looks like STOP if bus is not free yet */ + setscl(bit_adap, 1); + udelay(bit_adap->udelay); + setsda(bit_adap, 1); + ret = add_adapter(adap); if (ret < 0) return ret; -- cgit From 017fc4f6f4b7b70e443e7ef673732517ece111c8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Nov 2017 20:33:58 +0200 Subject: i2c: ismt: Use %pad specifier for dma_addr_t variables ...which takes care of proper format and size of the value. Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ismt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index b51adffa4841..c0d0f34d34f3 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -572,8 +572,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, return -EIO; } - dev_dbg(dev, " dma_addr = 0x%016llX\n", - (unsigned long long)dma_addr); + dev_dbg(dev, " dma_addr = %pad\n", &dma_addr); desc->dptr_low = lower_32_bits(dma_addr); desc->dptr_high = upper_32_bits(dma_addr); -- cgit From 5c015258478eaac484c2fc91bd1d06babacb1ec4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 28 Nov 2017 21:51:40 +0100 Subject: eeprom: at24: add basic regmap_i2c support This patch adds basic regmap support to be used by subsequent patches of this series. Signed-off-by: Heiner Kallweit Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/Kconfig | 1 + drivers/misc/eeprom/at24.c | 57 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index de58762097c4..68a1ac929917 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -4,6 +4,7 @@ config EEPROM_AT24 tristate "I2C EEPROMs / RAMs / ROMs from most vendors" depends on I2C && SYSFS select NVMEM + select REGMAP_I2C help Enable this driver to get read/write support to most I2C EEPROMs and compatible devices like FRAMs, SRAMs, ROMs etc. After you diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 4d63ac8a82e0..04c455ba4b77 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,11 @@ * which won't work on pure SMBus systems. */ +struct at24_client { + struct i2c_client *client; + struct regmap *regmap; +}; + struct at24_data { struct at24_platform_data chip; int use_smbus; @@ -81,7 +87,7 @@ struct at24_data { * Some chips tie up multiple I2C addresses; dummy devices reserve * them for us, and we'll use them with SMBus calls. */ - struct i2c_client *client[]; + struct at24_client client[]; }; /* @@ -274,7 +280,7 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24, *offset &= 0xff; } - return at24->client[i]; + return at24->client[i].client; } static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf, @@ -562,7 +568,7 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, static int at24_read(void *priv, unsigned int off, void *val, size_t count) { struct at24_data *at24 = priv; - struct device *dev = &at24->client[0]->dev; + struct device *dev = &at24->client[0].client->dev; char *buf = val; int ret; @@ -608,7 +614,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) static int at24_write(void *priv, unsigned int off, void *val, size_t count) { struct at24_data *at24 = priv; - struct device *dev = &at24->client[0]->dev; + struct device *dev = &at24->client[0].client->dev; char *buf = val; int ret; @@ -676,6 +682,16 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) } } +static const struct regmap_config regmap_config_8 = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct regmap_config regmap_config_16 = { + .reg_bits = 16, + .val_bits = 8, +}; + static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct at24_platform_data chip; @@ -686,6 +702,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) struct at24_data *at24; int err; unsigned i, num_addresses; + const struct regmap_config *config; u8 test_byte; if (client->dev.platform_data) { @@ -777,8 +794,13 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) num_addresses = DIV_ROUND_UP(chip.byte_len, (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256); + if (chip.flags & AT24_FLAG_ADDR16) + config = ®map_config_16; + else + config = ®map_config_8; + at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) + - num_addresses * sizeof(struct i2c_client *), GFP_KERNEL); + num_addresses * sizeof(struct at24_client), GFP_KERNEL); if (!at24) return -ENOMEM; @@ -788,6 +810,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->chip = chip; at24->num_addresses = num_addresses; + at24->client[0].client = client; + at24->client[0].regmap = devm_regmap_init_i2c(client, config); + if (IS_ERR(at24->client[0].regmap)) + return PTR_ERR(at24->client[0].regmap); + if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) { dev_err(&client->dev, "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); @@ -835,18 +862,22 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) } } - at24->client[0] = client; - /* use dummy devices for multiple-address chips */ for (i = 1; i < num_addresses; i++) { - at24->client[i] = i2c_new_dummy(client->adapter, - client->addr + i); - if (!at24->client[i]) { + at24->client[i].client = i2c_new_dummy(client->adapter, + client->addr + i); + if (!at24->client[i].client) { dev_err(&client->dev, "address 0x%02x unavailable\n", client->addr + i); err = -EADDRINUSE; goto err_clients; } + at24->client[i].regmap = devm_regmap_init_i2c( + at24->client[i].client, config); + if (IS_ERR(at24->client[i].regmap)) { + err = PTR_ERR(at24->client[i].regmap); + goto err_clients; + } } i2c_set_clientdata(client, at24); @@ -905,8 +936,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) err_clients: for (i = 1; i < num_addresses; i++) - if (at24->client[i]) - i2c_unregister_device(at24->client[i]); + if (at24->client[i].client) + i2c_unregister_device(at24->client[i].client); pm_runtime_disable(&client->dev); @@ -923,7 +954,7 @@ static int at24_remove(struct i2c_client *client) nvmem_unregister(at24->nvmem); for (i = 1; i < at24->num_addresses; i++) - i2c_unregister_device(at24->client[i]); + i2c_unregister_device(at24->client[i].client); pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); -- cgit From 4604948641384555da3ad5fc9f012e939e622c37 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 28 Nov 2017 21:51:42 +0100 Subject: eeprom: at24: change at24_translate_offset return type Change return type of at24_translate_offset to *at24_client to make member regmap accessible for subsequent patches of this series. Signed-off-by: Heiner Kallweit Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 04c455ba4b77..d00e9b509546 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -267,8 +267,8 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); * one "eeprom" file not four, but larger reads would fail when * they crossed certain pages. */ -static struct i2c_client *at24_translate_offset(struct at24_data *at24, - unsigned int *offset) +static struct at24_client *at24_translate_offset(struct at24_data *at24, + unsigned int *offset) { unsigned i; @@ -280,17 +280,19 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24, *offset &= 0xff; } - return at24->client[i].client; + return &at24->client[i]; } static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf, unsigned int offset, size_t count) { unsigned long timeout, read_time; + struct at24_client *at24_client; struct i2c_client *client; int status; - client = at24_translate_offset(at24, &offset); + at24_client = at24_translate_offset(at24, &offset); + client = at24_client->client; if (count > io_limit) count = io_limit; @@ -318,13 +320,15 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf, unsigned int offset, size_t count) { unsigned long timeout, read_time; + struct at24_client *at24_client; struct i2c_client *client; struct i2c_msg msg[2]; int status, i; u8 msgbuf[2]; memset(msg, 0, sizeof(msg)); - client = at24_translate_offset(at24, &offset); + at24_client = at24_translate_offset(at24, &offset); + client = at24_client->client; if (count > io_limit) count = io_limit; @@ -368,12 +372,14 @@ static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf, unsigned int offset, size_t count) { unsigned long timeout, read_time; + struct at24_client *at24_client; struct i2c_client *client; struct i2c_msg msg[2]; u8 addrbuf[2]; int status; - client = at24_translate_offset(at24, &offset); + at24_client = at24_translate_offset(at24, &offset); + client = at24_client->client; memset(msg, 0, sizeof(msg)); msg[0].addr = client->addr; @@ -421,12 +427,14 @@ static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf, unsigned int offset, size_t count) { unsigned long timeout, read_time; + struct at24_client *at24_client; struct i2c_client *client; struct i2c_msg msg[2]; u8 addrbuf[2]; int status; - client = at24_translate_offset(at24, &offset); + at24_client = at24_translate_offset(at24, &offset); + client = at24_client->client; memset(msg, 0, sizeof(msg)); msg[0].addr = client->addr; @@ -479,10 +487,12 @@ static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24, unsigned int offset, size_t count) { unsigned long timeout, write_time; + struct at24_client *at24_client; struct i2c_client *client; ssize_t status = 0; - client = at24_translate_offset(at24, &offset); + at24_client = at24_translate_offset(at24, &offset); + client = at24_client->client; count = at24_adjust_write_count(at24, offset, count); loop_until_timeout(timeout, write_time) { @@ -506,10 +516,12 @@ static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24, unsigned int offset, size_t count) { unsigned long timeout, write_time; + struct at24_client *at24_client; struct i2c_client *client; ssize_t status = 0; - client = at24_translate_offset(at24, &offset); + at24_client = at24_translate_offset(at24, &offset); + client = at24_client->client; loop_until_timeout(timeout, write_time) { status = i2c_smbus_write_byte_data(client, offset, buf[0]); @@ -530,12 +542,14 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, unsigned int offset, size_t count) { unsigned long timeout, write_time; + struct at24_client *at24_client; struct i2c_client *client; struct i2c_msg msg; ssize_t status = 0; int i = 0; - client = at24_translate_offset(at24, &offset); + at24_client = at24_translate_offset(at24, &offset); + client = at24_client->client; count = at24_adjust_write_count(at24, offset, count); msg.addr = client->addr; -- cgit From 8e5888e17f48d983eee27bd3ebf36fd03c8bb1e5 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 28 Nov 2017 21:51:45 +0100 Subject: eeprom: at24: add regmap-based write function Add a regmap-based write function. Signed-off-by: Heiner Kallweit Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index d00e9b509546..fa712279183b 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -538,6 +538,31 @@ static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24, return -ETIMEDOUT; } +static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct at24_client *at24_client; + struct i2c_client *client; + struct regmap *regmap; + int ret; + + at24_client = at24_translate_offset(at24, &offset); + regmap = at24_client->regmap; + client = at24_client->client; + count = at24_adjust_write_count(at24, offset, count); + + loop_until_timeout(timeout, write_time) { + ret = regmap_bulk_write(regmap, offset, buf, count); + dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n", + count, offset, ret, jiffies); + if (!ret) + return count; + } + + return -ETIMEDOUT; +} + static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, unsigned int offset, size_t count) { @@ -653,7 +678,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) while (count) { int status; - status = at24->write_func(at24, buf, off, count); + status = at24_regmap_write(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); pm_runtime_put(dev); -- cgit From d4297d6795779b0713203787eada5b8d9f0ce065 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 28 Nov 2017 21:51:47 +0100 Subject: eeprom: at24: remove old write functions Remove the old and now unused write functions. Signed-off-by: Heiner Kallweit Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 117 --------------------------------------------- 1 file changed, 117 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index fa712279183b..5f7d81054c11 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -64,11 +64,8 @@ struct at24_client { struct at24_data { struct at24_platform_data chip; int use_smbus; - int use_smbus_write; ssize_t (*read_func)(struct at24_data *, char *, unsigned int, size_t); - ssize_t (*write_func)(struct at24_data *, - const char *, unsigned int, size_t); /* * Lock protects against activities from other Linux tasks, @@ -76,7 +73,6 @@ struct at24_data { */ struct mutex lock; - u8 *writebuf; unsigned write_max; unsigned num_addresses; @@ -482,62 +478,6 @@ static size_t at24_adjust_write_count(struct at24_data *at24, return count; } -static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24, - const char *buf, - unsigned int offset, size_t count) -{ - unsigned long timeout, write_time; - struct at24_client *at24_client; - struct i2c_client *client; - ssize_t status = 0; - - at24_client = at24_translate_offset(at24, &offset); - client = at24_client->client; - count = at24_adjust_write_count(at24, offset, count); - - loop_until_timeout(timeout, write_time) { - status = i2c_smbus_write_i2c_block_data(client, - offset, count, buf); - if (status == 0) - status = count; - - dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", - count, offset, status, jiffies); - - if (status == count) - return count; - } - - return -ETIMEDOUT; -} - -static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24, - const char *buf, - unsigned int offset, size_t count) -{ - unsigned long timeout, write_time; - struct at24_client *at24_client; - struct i2c_client *client; - ssize_t status = 0; - - at24_client = at24_translate_offset(at24, &offset); - client = at24_client->client; - - loop_until_timeout(timeout, write_time) { - status = i2c_smbus_write_byte_data(client, offset, buf[0]); - if (status == 0) - status = count; - - dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", - count, offset, status, jiffies); - - if (status == count) - return count; - } - - return -ETIMEDOUT; -} - static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, unsigned int offset, size_t count) { @@ -563,47 +503,6 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, return -ETIMEDOUT; } -static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, - unsigned int offset, size_t count) -{ - unsigned long timeout, write_time; - struct at24_client *at24_client; - struct i2c_client *client; - struct i2c_msg msg; - ssize_t status = 0; - int i = 0; - - at24_client = at24_translate_offset(at24, &offset); - client = at24_client->client; - count = at24_adjust_write_count(at24, offset, count); - - msg.addr = client->addr; - msg.flags = 0; - - /* msg.buf is u8 and casts will mask the values */ - msg.buf = at24->writebuf; - if (at24->chip.flags & AT24_FLAG_ADDR16) - msg.buf[i++] = offset >> 8; - - msg.buf[i++] = offset; - memcpy(&msg.buf[i], buf, count); - msg.len = i + count; - - loop_until_timeout(timeout, write_time) { - status = i2c_transfer(client->adapter, &msg, 1); - if (status == 1) - status = count; - - dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", - count, offset, status, jiffies); - - if (status == count) - return count; - } - - return -ETIMEDOUT; -} - static int at24_read(void *priv, unsigned int off, void *val, size_t count) { struct at24_data *at24 = priv; @@ -845,7 +744,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) mutex_init(&at24->lock); at24->use_smbus = use_smbus; - at24->use_smbus_write = use_smbus_write; at24->chip = chip; at24->num_addresses = num_addresses; @@ -869,15 +767,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) : at24_eeprom_read_i2c; } - if (at24->use_smbus) { - if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA) - at24->write_func = at24_eeprom_write_smbus_block; - else - at24->write_func = at24_eeprom_write_smbus_byte; - } else { - at24->write_func = at24_eeprom_write_i2c; - } - writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { if (!use_smbus || use_smbus_write) { @@ -889,12 +778,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) write_max = I2C_SMBUS_BLOCK_MAX; at24->write_max = write_max; - - /* buffer (data + address at the beginning) */ - at24->writebuf = devm_kzalloc(&client->dev, - write_max + 2, GFP_KERNEL); - if (!at24->writebuf) - return -ENOMEM; } else { dev_warn(&client->dev, "cannot write due to controller restrictions."); -- cgit From 4bb5c13cc23c647c1fb6168d08de1fbda8f2357e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 28 Nov 2017 21:51:50 +0100 Subject: eeprom: at24: add regmap-based read function Add regmap-based read function and instead of using three different read functions (standard, mac, serial) use just one and factor out the read offset adjustment for mac and serial to at24_adjust_read_offset. Signed-off-by: Heiner Kallweit Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 57 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 5f7d81054c11..57a317b2e9a8 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -75,6 +75,7 @@ struct at24_data { unsigned write_max; unsigned num_addresses; + unsigned int offset_adj; struct nvmem_config nvmem_config; struct nvmem_device *nvmem; @@ -312,6 +313,36 @@ static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf, return -ETIMEDOUT; } +static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, read_time; + struct at24_client *at24_client; + struct i2c_client *client; + struct regmap *regmap; + int ret; + + at24_client = at24_translate_offset(at24, &offset); + regmap = at24_client->regmap; + client = at24_client->client; + + if (count > io_limit) + count = io_limit; + + /* adjust offset for mac and serial read ops */ + offset += at24->offset_adj; + + loop_until_timeout(timeout, read_time) { + ret = regmap_bulk_read(regmap, offset, buf, count); + dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", + count, offset, ret, jiffies); + if (!ret) + return count; + } + + return -ETIMEDOUT; +} + static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf, unsigned int offset, size_t count) { @@ -531,7 +562,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) while (count) { int status; - status = at24->read_func(at24, buf, off, count); + status = at24_regmap_read(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); pm_runtime_put(dev); @@ -620,6 +651,29 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) } } +static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len) +{ + if (flags & AT24_FLAG_MAC) { + /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */ + return 0xa0 - byte_len; + } else if (flags & AT24_FLAG_SERIAL && flags & AT24_FLAG_ADDR16) { + /* + * For 16 bit address pointers, the word address must contain + * a '10' sequence in bits 11 and 10 regardless of the + * intended position of the address pointer. + */ + return 0x0800; + } else if (flags & AT24_FLAG_SERIAL) { + /* + * Otherwise the word address must begin with a '10' sequence, + * regardless of the intended address. + */ + return 0x0080; + } else { + return 0; + } +} + static const struct regmap_config regmap_config_8 = { .reg_bits = 8, .val_bits = 8, @@ -746,6 +800,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->use_smbus = use_smbus; at24->chip = chip; at24->num_addresses = num_addresses; + at24->offset_adj = at24_get_offset_adj(chip.flags, chip.byte_len); at24->client[0].client = client; at24->client[0].regmap = devm_regmap_init_i2c(client, config); -- cgit From dd69a9da7120391f46dcf0c76a33e20279792a2f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 28 Nov 2017 21:51:52 +0100 Subject: eeprom: at24: remove old read functions Remove the old and now unused read functions. Signed-off-by: Heiner Kallweit Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 186 --------------------------------------------- 1 file changed, 186 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 57a317b2e9a8..8800a38e8d84 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -63,9 +63,6 @@ struct at24_client { struct at24_data { struct at24_platform_data chip; - int use_smbus; - - ssize_t (*read_func)(struct at24_data *, char *, unsigned int, size_t); /* * Lock protects against activities from other Linux tasks, @@ -280,39 +277,6 @@ static struct at24_client *at24_translate_offset(struct at24_data *at24, return &at24->client[i]; } -static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf, - unsigned int offset, size_t count) -{ - unsigned long timeout, read_time; - struct at24_client *at24_client; - struct i2c_client *client; - int status; - - at24_client = at24_translate_offset(at24, &offset); - client = at24_client->client; - - if (count > io_limit) - count = io_limit; - - /* Smaller eeproms can work given some SMBus extension calls */ - if (count > I2C_SMBUS_BLOCK_MAX) - count = I2C_SMBUS_BLOCK_MAX; - - loop_until_timeout(timeout, read_time) { - status = i2c_smbus_read_i2c_block_data_or_emulated(client, - offset, - count, buf); - - dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", - count, offset, status, jiffies); - - if (status == count) - return count; - } - - return -ETIMEDOUT; -} - static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, unsigned int offset, size_t count) { @@ -343,146 +307,6 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, return -ETIMEDOUT; } -static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf, - unsigned int offset, size_t count) -{ - unsigned long timeout, read_time; - struct at24_client *at24_client; - struct i2c_client *client; - struct i2c_msg msg[2]; - int status, i; - u8 msgbuf[2]; - - memset(msg, 0, sizeof(msg)); - at24_client = at24_translate_offset(at24, &offset); - client = at24_client->client; - - if (count > io_limit) - count = io_limit; - - /* - * When we have a better choice than SMBus calls, use a combined I2C - * message. Write address; then read up to io_limit data bytes. Note - * that read page rollover helps us here (unlike writes). msgbuf is - * u8 and will cast to our needs. - */ - i = 0; - if (at24->chip.flags & AT24_FLAG_ADDR16) - msgbuf[i++] = offset >> 8; - msgbuf[i++] = offset; - - msg[0].addr = client->addr; - msg[0].buf = msgbuf; - msg[0].len = i; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - - loop_until_timeout(timeout, read_time) { - status = i2c_transfer(client->adapter, msg, 2); - if (status == 2) - status = count; - - dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", - count, offset, status, jiffies); - - if (status == count) - return count; - } - - return -ETIMEDOUT; -} - -static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf, - unsigned int offset, size_t count) -{ - unsigned long timeout, read_time; - struct at24_client *at24_client; - struct i2c_client *client; - struct i2c_msg msg[2]; - u8 addrbuf[2]; - int status; - - at24_client = at24_translate_offset(at24, &offset); - client = at24_client->client; - - memset(msg, 0, sizeof(msg)); - msg[0].addr = client->addr; - msg[0].buf = addrbuf; - - /* - * The address pointer of the device is shared between the regular - * EEPROM array and the serial number block. The dummy write (part of - * the sequential read protocol) ensures the address pointer is reset - * to the desired position. - */ - if (at24->chip.flags & AT24_FLAG_ADDR16) { - /* - * For 16 bit address pointers, the word address must contain - * a '10' sequence in bits 11 and 10 regardless of the - * intended position of the address pointer. - */ - addrbuf[0] = 0x08; - addrbuf[1] = offset; - msg[0].len = 2; - } else { - /* - * Otherwise the word address must begin with a '10' sequence, - * regardless of the intended address. - */ - addrbuf[0] = 0x80 + offset; - msg[0].len = 1; - } - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - - loop_until_timeout(timeout, read_time) { - status = i2c_transfer(client->adapter, msg, 2); - if (status == 2) - return count; - } - - return -ETIMEDOUT; -} - -static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf, - unsigned int offset, size_t count) -{ - unsigned long timeout, read_time; - struct at24_client *at24_client; - struct i2c_client *client; - struct i2c_msg msg[2]; - u8 addrbuf[2]; - int status; - - at24_client = at24_translate_offset(at24, &offset); - client = at24_client->client; - - memset(msg, 0, sizeof(msg)); - msg[0].addr = client->addr; - msg[0].buf = addrbuf; - /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */ - addrbuf[0] = 0xa0 - at24->chip.byte_len + offset; - msg[0].len = 1; - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - - loop_until_timeout(timeout, read_time) { - status = i2c_transfer(client->adapter, msg, 2); - if (status == 2) - return count; - } - - return -ETIMEDOUT; -} - /* * Note that if the hardware write-protect pin is pulled high, the whole * chip is normally write protected. But there are plenty of product @@ -797,7 +621,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) return -ENOMEM; mutex_init(&at24->lock); - at24->use_smbus = use_smbus; at24->chip = chip; at24->num_addresses = num_addresses; at24->offset_adj = at24_get_offset_adj(chip.flags, chip.byte_len); @@ -813,15 +636,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) return -EINVAL; } - if (chip.flags & AT24_FLAG_SERIAL) { - at24->read_func = at24_eeprom_read_serial; - } else if (chip.flags & AT24_FLAG_MAC) { - at24->read_func = at24_eeprom_read_mac; - } else { - at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus - : at24_eeprom_read_i2c; - } - writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { if (!use_smbus || use_smbus_write) { -- cgit From a23727cb68e4bcd1eefcdab5459331db32516abd Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 28 Nov 2017 21:51:54 +0100 Subject: eeprom: at24: remove now unneeded smbus-related code Remove remaining now unneeded code dealing with SMBUS details. Signed-off-by: Heiner Kallweit Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 56 +++++++--------------------------------------- 1 file changed, 8 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 8800a38e8d84..3fd26d7cb50e 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -513,8 +513,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) struct at24_platform_data chip; kernel_ulong_t magic = 0; bool writable; - int use_smbus = 0; - int use_smbus_write = 0; struct at24_data *at24; int err; unsigned i, num_addresses; @@ -576,33 +574,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) if (chip.flags & AT24_FLAG_MAC && chip.byte_len == 4) chip.byte_len = 6; - /* Use I2C operations unless we're stuck with SMBus extensions. */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - if (chip.flags & AT24_FLAG_ADDR16) - return -EPFNOSUPPORT; - - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; - } else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_WORD_DATA)) { - use_smbus = I2C_SMBUS_WORD_DATA; - } else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - use_smbus = I2C_SMBUS_BYTE_DATA; - } else { - return -EPFNOSUPPORT; - } - - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { - use_smbus_write = I2C_SMBUS_I2C_BLOCK_DATA; - } else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { - use_smbus_write = I2C_SMBUS_BYTE_DATA; - chip.page_size = 1; - } - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) && + !i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) + chip.page_size = 1; if (chip.flags & AT24_FLAG_TAKE8ADDR) num_addresses = 8; @@ -638,19 +613,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { - if (!use_smbus || use_smbus_write) { - - unsigned write_max = chip.page_size; - - if (write_max > io_limit) - write_max = io_limit; - if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) - write_max = I2C_SMBUS_BLOCK_MAX; - at24->write_max = write_max; - } else { - dev_warn(&client->dev, - "cannot write due to controller restrictions."); - } + at24->write_max = min_t(unsigned int, chip.page_size, io_limit); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) && + at24->write_max > I2C_SMBUS_BLOCK_MAX) + at24->write_max = I2C_SMBUS_BLOCK_MAX; } /* use dummy devices for multiple-address chips */ @@ -712,12 +678,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n", chip.byte_len, client->name, writable ? "writable" : "read-only", at24->write_max); - if (use_smbus == I2C_SMBUS_WORD_DATA || - use_smbus == I2C_SMBUS_BYTE_DATA) { - dev_notice(&client->dev, "Falling back to %s reads, " - "performance will suffer\n", use_smbus == - I2C_SMBUS_WORD_DATA ? "word" : "byte"); - } /* export data to kernel code */ if (chip.setup) -- cgit From e32213fbc5432c28268dced0dc8735dcf8532d36 Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Fri, 8 Dec 2017 11:28:30 -0500 Subject: eeprom: at24: support eeproms that do not auto-rollover reads Some multi-address eeproms in the at24 family may not automatically roll-over reads to the next slave address. On those eeproms, reads that straddle slave boundaries will not work correctly. Solution: Mark such eeproms with a flag that prevents reads straddling slave boundaries. Add the AT24_FLAG_NO_RDROL flag to the eeprom entry in the device_id table, or add 'no-read-rollover' to the eeprom devicetree entry. Note that I have not personally enountered an at24 chip that does not support read rollovers. They may or may not exist. However, my hardware requires this functionality because of a quirk. Signed-off-by: Sven Van Asbroeck Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 3fd26d7cb50e..848fda8be314 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -251,15 +251,6 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); * Slave address and byte offset derive from the offset. Always * set the byte address; on a multi-master board, another master * may have changed the chip's "current" address pointer. - * - * REVISIT some multi-address chips don't rollover page reads to - * the next slave address, so we may need to truncate the count. - * Those chips might need another quirk flag. - * - * If the real hardware used four adjacent 24c02 chips and that - * were misconfigured as one 24c08, that would be a similar effect: - * one "eeprom" file not four, but larger reads would fail when - * they crossed certain pages. */ static struct at24_client *at24_translate_offset(struct at24_data *at24, unsigned int *offset) @@ -277,6 +268,30 @@ static struct at24_client *at24_translate_offset(struct at24_data *at24, return &at24->client[i]; } +static size_t at24_adjust_read_count(struct at24_data *at24, + unsigned int offset, size_t count) +{ + unsigned int bits; + size_t remainder; + + /* + * In case of multi-address chips that don't rollover reads to + * the next slave address: truncate the count to the slave boundary, + * so that the read never straddles slaves. + */ + if (at24->chip.flags & AT24_FLAG_NO_RDROL) { + bits = (at24->chip.flags & AT24_FLAG_ADDR16) ? 16 : 8; + remainder = BIT(bits) - offset; + if (count > remainder) + count = remainder; + } + + if (count > io_limit) + count = io_limit; + + return count; +} + static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, unsigned int offset, size_t count) { @@ -289,9 +304,7 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, at24_client = at24_translate_offset(at24, &offset); regmap = at24_client->regmap; client = at24_client->client; - - if (count > io_limit) - count = io_limit; + count = at24_adjust_read_count(at24, offset, count); /* adjust offset for mac and serial read ops */ offset += at24->offset_adj; @@ -457,6 +470,8 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) if (device_property_present(dev, "read-only")) chip->flags |= AT24_FLAG_READONLY; + if (device_property_present(dev, "no-read-rollover")) + chip->flags |= AT24_FLAG_NO_RDROL; err = device_property_read_u32(dev, "size", &val); if (!err) -- cgit From aa4ce22897e159ec7ecf396c199ba0edcef886c3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 13 Dec 2017 11:56:23 +0100 Subject: eeprom: at24: fix coding style issues Fix issues reported by checkpatch for at24.c. Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 848fda8be314..b30db99cd951 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -70,8 +70,8 @@ struct at24_data { */ struct mutex lock; - unsigned write_max; - unsigned num_addresses; + unsigned int write_max; + unsigned int num_addresses; unsigned int offset_adj; struct nvmem_config nvmem_config; @@ -93,7 +93,7 @@ struct at24_data { * * This value is forced to be a power of two so that writes align on pages. */ -static unsigned io_limit = 128; +static unsigned int io_limit = 128; module_param(io_limit, uint, 0); MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)"); @@ -101,7 +101,7 @@ MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)"); * Specs often allow 5 msec for a page write, sometimes 20 msec; * it's important to recover from write timeouts. */ -static unsigned write_timeout = 25; +static unsigned int write_timeout = 25; module_param(write_timeout, uint, 0); MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); @@ -111,8 +111,8 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); #define AT24_BITMASK(x) (BIT(x) - 1) /* create non-zero magic value for given eeprom parameters */ -#define AT24_DEVICE_MAGIC(_len, _flags) \ - ((1 << AT24_SIZE_FLAGS | (_flags)) \ +#define AT24_DEVICE_MAGIC(_len, _flags) \ + ((1 << AT24_SIZE_FLAGS | (_flags)) \ << AT24_SIZE_BYTELEN | ilog2(_len)) /* @@ -255,7 +255,7 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); static struct at24_client *at24_translate_offset(struct at24_data *at24, unsigned int *offset) { - unsigned i; + unsigned int i; if (at24->chip.flags & AT24_FLAG_ADDR16) { i = *offset >> 16; @@ -332,7 +332,7 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, static size_t at24_adjust_write_count(struct at24_data *at24, unsigned int offset, size_t count) { - unsigned next_page; + unsigned int next_page; /* write_max is at most a page */ if (count > at24->write_max) @@ -530,7 +530,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) bool writable; struct at24_data *at24; int err; - unsigned i, num_addresses; + unsigned int i, num_addresses; const struct regmap_config *config; u8 test_byte; -- cgit From ec3c2d518b163dd2be48ac1fee8d7f1686cd769f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 18 Dec 2017 18:16:46 +0100 Subject: eeprom: at24: use a common prefix for all symbols in at24.c There are a couple symbols defined in the driver source file which are missing the at24_ prefix. This patch fixes that. For module params: use module_param_named() in order to not break userspace. Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index b30db99cd951..657074ec0e64 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -93,17 +93,17 @@ struct at24_data { * * This value is forced to be a power of two so that writes align on pages. */ -static unsigned int io_limit = 128; -module_param(io_limit, uint, 0); -MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)"); +static unsigned int at24_io_limit = 128; +module_param_named(io_limit, at24_io_limit, uint, 0); +MODULE_PARM_DESC(at24_io_limit, "Maximum bytes per I/O (default 128)"); /* * Specs often allow 5 msec for a page write, sometimes 20 msec; * it's important to recover from write timeouts. */ -static unsigned int write_timeout = 25; -module_param(write_timeout, uint, 0); -MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); +static unsigned int at24_write_timeout = 25; +module_param_named(write_timeout, at24_write_timeout, uint, 0); +MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); #define AT24_SIZE_BYTELEN 5 #define AT24_SIZE_FLAGS 8 @@ -126,8 +126,9 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); * iteration of processing the request. Both should be unsigned integers * holding at least 32 bits. */ -#define loop_until_timeout(tout, op_time) \ - for (tout = jiffies + msecs_to_jiffies(write_timeout), op_time = 0; \ +#define at24_loop_until_timeout(tout, op_time) \ + for (tout = jiffies + msecs_to_jiffies(at24_write_timeout), \ + op_time = 0; \ op_time ? time_before(op_time, tout) : true; \ usleep_range(1000, 1500), op_time = jiffies) @@ -286,8 +287,8 @@ static size_t at24_adjust_read_count(struct at24_data *at24, count = remainder; } - if (count > io_limit) - count = io_limit; + if (count > at24_io_limit) + count = at24_io_limit; return count; } @@ -309,7 +310,7 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, /* adjust offset for mac and serial read ops */ offset += at24->offset_adj; - loop_until_timeout(timeout, read_time) { + at24_loop_until_timeout(timeout, read_time) { ret = regmap_bulk_read(regmap, offset, buf, count); dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", count, offset, ret, jiffies); @@ -360,7 +361,7 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, client = at24_client->client; count = at24_adjust_write_count(at24, offset, count); - loop_until_timeout(timeout, write_time) { + at24_loop_until_timeout(timeout, write_time) { ret = regmap_bulk_write(regmap, offset, buf, count); dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n", count, offset, ret, jiffies); @@ -628,7 +629,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { - at24->write_max = min_t(unsigned int, chip.page_size, io_limit); + at24->write_max = min_t(unsigned int, + chip.page_size, at24_io_limit); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) && at24->write_max > I2C_SMBUS_BLOCK_MAX) at24->write_max = I2C_SMBUS_BLOCK_MAX; @@ -743,12 +745,12 @@ static struct i2c_driver at24_driver = { static int __init at24_init(void) { - if (!io_limit) { - pr_err("at24: io_limit must not be 0!\n"); + if (!at24_io_limit) { + pr_err("at24: at24_io_limit must not be 0!\n"); return -EINVAL; } - io_limit = rounddown_pow_of_two(io_limit); + at24_io_limit = rounddown_pow_of_two(at24_io_limit); return i2c_add_driver(&at24_driver); } module_init(at24_init); -- cgit From eef6939849b04bb1ba36f35f5c864eb0a66d1d83 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 18 Dec 2017 18:24:43 +0100 Subject: eeprom: at24: code shrink A regmap_config struct is pretty big and declaring two of them statically just to tweak the reg_bits value adds unnecessary bloat. Declare the regmap config locally in at24_probe() instead. Bloat-o-meter output for ARM: add/remove: 0/2 grow/shrink: 1/0 up/down: 4/-272 (-268) Function old new delta at24_probe 1560 1564 +4 regmap_config_8 136 - -136 regmap_config_16 136 - -136 Total: Before=7012, After=6744, chg -3.82% Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 657074ec0e64..b44a3d2b2b20 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -514,16 +514,6 @@ static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len) } } -static const struct regmap_config regmap_config_8 = { - .reg_bits = 8, - .val_bits = 8, -}; - -static const struct regmap_config regmap_config_16 = { - .reg_bits = 16, - .val_bits = 8, -}; - static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct at24_platform_data chip; @@ -532,7 +522,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) struct at24_data *at24; int err; unsigned int i, num_addresses; - const struct regmap_config *config; + struct regmap_config regmap_config = { }; u8 test_byte; if (client->dev.platform_data) { @@ -601,10 +591,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) num_addresses = DIV_ROUND_UP(chip.byte_len, (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256); - if (chip.flags & AT24_FLAG_ADDR16) - config = ®map_config_16; - else - config = ®map_config_8; + regmap_config.val_bits = 8; + regmap_config.reg_bits = (chip.flags & AT24_FLAG_ADDR16) ? 16 : 8; at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) + num_addresses * sizeof(struct at24_client), GFP_KERNEL); @@ -617,7 +605,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->offset_adj = at24_get_offset_adj(chip.flags, chip.byte_len); at24->client[0].client = client; - at24->client[0].regmap = devm_regmap_init_i2c(client, config); + at24->client[0].regmap = devm_regmap_init_i2c(client, ®map_config); if (IS_ERR(at24->client[0].regmap)) return PTR_ERR(at24->client[0].regmap); @@ -647,7 +635,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_clients; } at24->client[i].regmap = devm_regmap_init_i2c( - at24->client[i].client, config); + at24->client[i].client, + ®map_config); if (IS_ERR(at24->client[i].regmap)) { err = PTR_ERR(at24->client[i].regmap); goto err_clients; -- cgit From b680f4fa74496ac01e0f77e612a16d1ea892fd2a Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Wed, 20 Dec 2017 11:48:56 -0500 Subject: eeprom: at24: convert magic numbers to structs Fundamental properties such as capacity and page size differ among at24-type chips. But these chips do not have an id register, so this can't be discovered at runtime. Traditionally, at24-type eeprom properties were determined in two ways: - by passing a 'struct at24_platform_data' via platform_data, or - by naming the chip type in the devicetree, which passes a 'magic number' to probe(), which is then converted to a 'struct at24_platform_data'. Recently a bug was discovered because the magic number rounds down all chip sizes to the lowest power of two. This was addressed by a work-around commit 5478e478eee3 ("eeprom: at24: correctly set the size for at24mac402"), with the wish that magic numbers should over time be converted to structs. This patch replaces the magic numbers with 'struct at24_chip_data'. Signed-off-by: Sven Van Asbroeck Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 221 ++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index b44a3d2b2b20..b1f78b99f8a1 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -105,16 +105,6 @@ static unsigned int at24_write_timeout = 25; module_param_named(write_timeout, at24_write_timeout, uint, 0); MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); -#define AT24_SIZE_BYTELEN 5 -#define AT24_SIZE_FLAGS 8 - -#define AT24_BITMASK(x) (BIT(x) - 1) - -/* create non-zero magic value for given eeprom parameters */ -#define AT24_DEVICE_MAGIC(_len, _flags) \ - ((1 << AT24_SIZE_FLAGS | (_flags)) \ - << AT24_SIZE_BYTELEN | ilog2(_len)) - /* * Both reads and writes fail if the previous write didn't complete yet. This * macro loops a few times waiting at least long enough for one entire page @@ -132,113 +122,108 @@ MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); op_time ? time_before(op_time, tout) : true; \ usleep_range(1000, 1500), op_time = jiffies) +struct at24_chip_data { + /* + * these fields mirror their equivalents in + * struct at24_platform_data + */ + u32 byte_len; + u8 flags; +}; + +#define AT24_CHIP_DATA(_name, _len, _flags) \ + static const struct at24_chip_data _name = { \ + .byte_len = _len, .flags = _flags, \ + } + +/* needs 8 addresses as A0-A2 are ignored */ +AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR); +/* old variants can't be handled with this generic entry! */ +AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs01, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs02, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24mac402, 48 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24mac602, 64 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY); +/* spd is a 24c02 in memory DIMMs */ +AT24_CHIP_DATA(at24_data_spd, 2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO); +AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs04, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +/* 24rf08 quirk is handled at i2c-core */ +AT24_CHIP_DATA(at24_data_24c08, 8192 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs08, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c16, 16384 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs16, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c32, 32768 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24cs32, 16, + AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c64, 65536 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24cs64, 16, + AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16); +/* identical to 24c08 ? */ +AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0); + static const struct i2c_device_id at24_ids[] = { - /* needs 8 addresses as A0-A2 are ignored */ - { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) }, - /* old variants can't be handled with this generic entry! */ - { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) }, - { "24cs01", AT24_DEVICE_MAGIC(16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, - { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, - { "24cs02", AT24_DEVICE_MAGIC(16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, - { "24mac402", AT24_DEVICE_MAGIC(48 / 8, - AT24_FLAG_MAC | AT24_FLAG_READONLY) }, - { "24mac602", AT24_DEVICE_MAGIC(64 / 8, - AT24_FLAG_MAC | AT24_FLAG_READONLY) }, - /* spd is a 24c02 in memory DIMMs */ - { "spd", AT24_DEVICE_MAGIC(2048 / 8, - AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, - { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, - { "24cs04", AT24_DEVICE_MAGIC(16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, - /* 24rf08 quirk is handled at i2c-core */ - { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, - { "24cs08", AT24_DEVICE_MAGIC(16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, - { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) }, - { "24cs16", AT24_DEVICE_MAGIC(16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, - { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) }, - { "24cs32", AT24_DEVICE_MAGIC(16, - AT24_FLAG_ADDR16 | - AT24_FLAG_SERIAL | - AT24_FLAG_READONLY) }, - { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) }, - { "24cs64", AT24_DEVICE_MAGIC(16, - AT24_FLAG_ADDR16 | - AT24_FLAG_SERIAL | - AT24_FLAG_READONLY) }, - { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) }, - { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) }, - { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) }, - { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) }, - { "at24", 0 }, + { "24c00", (kernel_ulong_t)&at24_data_24c00 }, + { "24c01", (kernel_ulong_t)&at24_data_24c01 }, + { "24cs01", (kernel_ulong_t)&at24_data_24cs01 }, + { "24c02", (kernel_ulong_t)&at24_data_24c02 }, + { "24cs02", (kernel_ulong_t)&at24_data_24cs02 }, + { "24mac402", (kernel_ulong_t)&at24_data_24mac402 }, + { "24mac602", (kernel_ulong_t)&at24_data_24mac602 }, + { "spd", (kernel_ulong_t)&at24_data_spd }, + { "24c04", (kernel_ulong_t)&at24_data_24c04 }, + { "24cs04", (kernel_ulong_t)&at24_data_24cs04 }, + { "24c08", (kernel_ulong_t)&at24_data_24c08 }, + { "24cs08", (kernel_ulong_t)&at24_data_24cs08 }, + { "24c16", (kernel_ulong_t)&at24_data_24c16 }, + { "24cs16", (kernel_ulong_t)&at24_data_24cs16 }, + { "24c32", (kernel_ulong_t)&at24_data_24c32 }, + { "24cs32", (kernel_ulong_t)&at24_data_24cs32 }, + { "24c64", (kernel_ulong_t)&at24_data_24c64 }, + { "24cs64", (kernel_ulong_t)&at24_data_24cs64 }, + { "24c128", (kernel_ulong_t)&at24_data_24c128 }, + { "24c256", (kernel_ulong_t)&at24_data_24c256 }, + { "24c512", (kernel_ulong_t)&at24_data_24c512 }, + { "24c1024", (kernel_ulong_t)&at24_data_24c1024 }, + { "at24", 0 }, { /* END OF LIST */ } }; MODULE_DEVICE_TABLE(i2c, at24_ids); static const struct of_device_id at24_of_match[] = { - { - .compatible = "atmel,24c00", - .data = (void *)AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) - }, - { - .compatible = "atmel,24c01", - .data = (void *)AT24_DEVICE_MAGIC(1024 / 8, 0) - }, - { - .compatible = "atmel,24c02", - .data = (void *)AT24_DEVICE_MAGIC(2048 / 8, 0) - }, - { - .compatible = "atmel,spd", - .data = (void *)AT24_DEVICE_MAGIC(2048 / 8, - AT24_FLAG_READONLY | AT24_FLAG_IRUGO) - }, - { - .compatible = "atmel,24c04", - .data = (void *)AT24_DEVICE_MAGIC(4096 / 8, 0) - }, - { - .compatible = "atmel,24c08", - .data = (void *)AT24_DEVICE_MAGIC(8192 / 8, 0) - }, - { - .compatible = "atmel,24c16", - .data = (void *)AT24_DEVICE_MAGIC(16384 / 8, 0) - }, - { - .compatible = "atmel,24c32", - .data = (void *)AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) - }, - { - .compatible = "atmel,24c64", - .data = (void *)AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) - }, - { - .compatible = "atmel,24c128", - .data = (void *)AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) - }, - { - .compatible = "atmel,24c256", - .data = (void *)AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) - }, - { - .compatible = "atmel,24c512", - .data = (void *)AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) - }, - { - .compatible = "atmel,24c1024", - .data = (void *)AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) - }, - { }, + { .compatible = "atmel,24c00", .data = &at24_data_24c00 }, + { .compatible = "atmel,24c01", .data = &at24_data_24c01 }, + { .compatible = "atmel,24c02", .data = &at24_data_24c02 }, + { .compatible = "atmel,spd", .data = &at24_data_spd }, + { .compatible = "atmel,24c04", .data = &at24_data_24c04 }, + { .compatible = "atmel,24c08", .data = &at24_data_24c08 }, + { .compatible = "atmel,24c16", .data = &at24_data_24c16 }, + { .compatible = "atmel,24c32", .data = &at24_data_24c32 }, + { .compatible = "atmel,24c64", .data = &at24_data_24c64 }, + { .compatible = "atmel,24c128", .data = &at24_data_24c128 }, + { .compatible = "atmel,24c256", .data = &at24_data_24c256 }, + { .compatible = "atmel,24c512", .data = &at24_data_24c512 }, + { .compatible = "atmel,24c1024", .data = &at24_data_24c1024 }, + { /* END OF LIST */ }, }; MODULE_DEVICE_TABLE(of, at24_of_match); static const struct acpi_device_id at24_acpi_ids[] = { - { "INT3499", AT24_DEVICE_MAGIC(8192 / 8, 0) }, - { } + { "INT3499", (kernel_ulong_t)&at24_data_INT3499 }, + { /* END OF LIST */ } }; MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); @@ -516,8 +501,8 @@ static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len) static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct at24_platform_data chip; - kernel_ulong_t magic = 0; + struct at24_platform_data chip = { 0 }; + const struct at24_chip_data *cd = NULL; bool writable; struct at24_data *at24; int err; @@ -535,28 +520,22 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) */ if (client->dev.of_node && of_match_device(at24_of_match, &client->dev)) { - magic = (kernel_ulong_t) - of_device_get_match_data(&client->dev); + cd = of_device_get_match_data(&client->dev); } else if (id) { - magic = id->driver_data; + cd = (void *)id->driver_data; } else { const struct acpi_device_id *aid; aid = acpi_match_device(at24_acpi_ids, &client->dev); if (aid) - magic = aid->driver_data; + cd = (void *)aid->driver_data; } - if (!magic) + if (!cd) return -ENODEV; - chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN)); - magic >>= AT24_SIZE_BYTELEN; - chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS); - + chip.byte_len = cd->byte_len; + chip.flags = cd->flags; at24_get_pdata(&client->dev, &chip); - - chip.setup = NULL; - chip.context = NULL; } if (!is_power_of_2(chip.byte_len)) -- cgit From ef542e59d7a11d343149b60609f422effede9d80 Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Fri, 8 Dec 2017 16:25:06 -0500 Subject: eeprom: at24: remove temporary fix for at24mac402 size The chip size passed via devicetree, i2c, or acpi device ids is now no longer limited to a power of two. So the temporary fix can be removed. Signed-off-by: Sven Van Asbroeck Signed-off-by: Bartosz Golaszewski --- drivers/misc/eeprom/at24.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index b1f78b99f8a1..581ba640c741 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -549,16 +549,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_warn(&client->dev, "page_size looks suspicious (no power of 2)!\n"); - /* - * REVISIT: the size of the EUI-48 byte array is 6 in at24mac402, while - * the call to ilog2() in AT24_DEVICE_MAGIC() rounds it down to 4. - * - * Eventually we'll get rid of the magic values altoghether in favor of - * real structs, but for now just manually set the right size. - */ - if (chip.flags & AT24_FLAG_MAC && chip.byte_len == 4) - chip.byte_len = 6; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) && !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) -- cgit From 6ce261e87fe14d551aae36e15171c60c823ba10a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 19 Dec 2017 11:28:54 +0100 Subject: eeprom: at24: add support for the write-protect pin AT24 EEPROMs have a write-protect pin, which - when pulled high - inhibits writes to the upper quadrant of memory (although it has been observed that on some chips it disables writing to the entire memory range). On some boards, this pin is connected to a GPIO and pulled high by default, which forces the user to manually change its state before writing. On linux this means that we either need to hog the line all the time, or set the GPIO value before writing from outside of the at24 driver. Make the driver check if the write-protect GPIO was defined in the device tree and pull it low whenever writing to the EEPROM. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko --- drivers/misc/eeprom/at24.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 581ba640c741..e79833d62284 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -27,6 +27,7 @@ #include #include #include +#include /* * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. @@ -77,6 +78,8 @@ struct at24_data { struct nvmem_config nvmem_config; struct nvmem_device *nvmem; + struct gpio_desc *wp_gpio; + /* * Some chips tie up multiple I2C addresses; dummy devices reserve * them for us, and we'll use them with SMBus calls. @@ -427,12 +430,14 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) * from this host, but not from other I2C masters. */ mutex_lock(&at24->lock); + gpiod_set_value_cansleep(at24->wp_gpio, 0); while (count) { int status; status = at24_regmap_write(at24, buf, off, count); if (status < 0) { + gpiod_set_value_cansleep(at24->wp_gpio, 1); mutex_unlock(&at24->lock); pm_runtime_put(dev); return status; @@ -442,6 +447,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) count -= status; } + gpiod_set_value_cansleep(at24->wp_gpio, 1); mutex_unlock(&at24->lock); pm_runtime_put(dev); @@ -573,6 +579,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->num_addresses = num_addresses; at24->offset_adj = at24_get_offset_adj(chip.flags, chip.byte_len); + at24->wp_gpio = devm_gpiod_get_optional(&client->dev, + "wp", GPIOD_OUT_HIGH); + if (IS_ERR(at24->wp_gpio)) + return PTR_ERR(at24->wp_gpio); + at24->client[0].client = client; at24->client[0].regmap = devm_regmap_init_i2c(client, ®map_config); if (IS_ERR(at24->client[0].regmap)) -- cgit From 0f30aca72c3b68f4b6a443193b574f14106cd61e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 28 Dec 2017 11:49:13 +0100 Subject: eeprom: at24: extend the list of chips supported in DT Add all supported at24 variants to the of_match table. Signed-off-by: Bartosz Golaszewski Reviewed-by: Javier Martinez Canillas --- drivers/misc/eeprom/at24.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index e79833d62284..01f9c4921c50 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -209,13 +209,22 @@ MODULE_DEVICE_TABLE(i2c, at24_ids); static const struct of_device_id at24_of_match[] = { { .compatible = "atmel,24c00", .data = &at24_data_24c00 }, { .compatible = "atmel,24c01", .data = &at24_data_24c01 }, + { .compatible = "atmel,24cs01", .data = &at24_data_24cs01 }, { .compatible = "atmel,24c02", .data = &at24_data_24c02 }, + { .compatible = "atmel,24cs02", .data = &at24_data_24cs02 }, + { .compatible = "atmel,24mac402", .data = &at24_data_24mac402 }, + { .compatible = "atmel,24mac602", .data = &at24_data_24mac602 }, { .compatible = "atmel,spd", .data = &at24_data_spd }, { .compatible = "atmel,24c04", .data = &at24_data_24c04 }, + { .compatible = "atmel,24cs04", .data = &at24_data_24cs04 }, { .compatible = "atmel,24c08", .data = &at24_data_24c08 }, + { .compatible = "atmel,24cs08", .data = &at24_data_24cs08 }, { .compatible = "atmel,24c16", .data = &at24_data_24c16 }, + { .compatible = "atmel,24cs16", .data = &at24_data_24cs16 }, { .compatible = "atmel,24c32", .data = &at24_data_24c32 }, + { .compatible = "atmel,24cs32", .data = &at24_data_24cs32 }, { .compatible = "atmel,24c64", .data = &at24_data_24c64 }, + { .compatible = "atmel,24cs64", .data = &at24_data_24cs64 }, { .compatible = "atmel,24c128", .data = &at24_data_24c128 }, { .compatible = "atmel,24c256", .data = &at24_data_24c256 }, { .compatible = "atmel,24c512", .data = &at24_data_24c512 }, -- cgit From 3da941b048bd105fd2803f0e0cd77d59f731fafc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 23 Dec 2017 20:44:27 +0100 Subject: pinctrl: at91: Delete an error message for a failed memory allocation in at91_pinctrl_mux_mask() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 03492e3c09fa..297f1d161211 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1050,10 +1050,8 @@ static int at91_pinctrl_mux_mask(struct at91_pinctrl *info, info->nmux = size / gpio_banks; info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL); - if (!info->mux_mask) { - dev_err(info->dev, "could not alloc mux_mask\n"); + if (!info->mux_mask) return -ENOMEM; - } ret = of_property_read_u32_array(np, "atmel,mux-mask", info->mux_mask, size); -- cgit From 5896c8d7c828ff75f85069390eae2aa09f1353e4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 23 Dec 2017 21:16:42 +0100 Subject: pinctrl: palmas: Delete an error message for a failed memory allocation in palmas_pinctrl_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-palmas.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c index 4d6a5015b927..d42f18cb1bc7 100644 --- a/drivers/pinctrl/pinctrl-palmas.c +++ b/drivers/pinctrl/pinctrl-palmas.c @@ -1012,10 +1012,8 @@ static int palmas_pinctrl_probe(struct platform_device *pdev) } pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL); - if (!pci) { - dev_err(&pdev->dev, "Malloc for pci failed\n"); + if (!pci) return -ENOMEM; - } pci->dev = &pdev->dev; pci->palmas = dev_get_drvdata(pdev->dev.parent); -- cgit From 98c8ee73fec3c76a36b3e415d517c998b61a1a20 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 23 Dec 2017 22:02:47 +0100 Subject: pinctrl: rockchip: Delete error messages for a failed memory allocation in two functions Omit extra messages for a memory allocation failure in these functions. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 073de6a9ed34..fd1f363a8c2b 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -2408,18 +2408,14 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, info->functions = devm_kzalloc(dev, info->nfunctions * sizeof(struct rockchip_pmx_func), GFP_KERNEL); - if (!info->functions) { - dev_err(dev, "failed to allocate memory for function list\n"); + if (!info->functions) return -EINVAL; - } info->groups = devm_kzalloc(dev, info->ngroups * sizeof(struct rockchip_pin_group), GFP_KERNEL); - if (!info->groups) { - dev_err(dev, "failed allocate memory for ping group list\n"); + if (!info->groups) return -EINVAL; - } i = 0; @@ -2455,10 +2451,9 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * info->ctrl->nr_pins, GFP_KERNEL); - if (!pindesc) { - dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + if (!pindesc) return -ENOMEM; - } + ctrldesc->pins = pindesc; ctrldesc->npins = info->ctrl->nr_pins; -- cgit From 283b7ac92b49bc7df6e3896d44dd81d80e4e3487 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 23 Dec 2017 22:07:30 +0100 Subject: pinctrl: rockchip: Improve a size determination in rockchip_pinctrl_probe() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index fd1f363a8c2b..b65e43b8b32e 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -3166,7 +3166,7 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) return -ENODEV; } - info = devm_kzalloc(dev, sizeof(struct rockchip_pinctrl), GFP_KERNEL); + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; -- cgit From 85dc397a2441dd0ea6f01732310b0609f444bdc5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 23 Dec 2017 22:22:54 +0100 Subject: pinctrl: rockchip: Fix a typo in four comment lines Adjust words in these descriptions. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index b65e43b8b32e..3924779f5578 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -136,7 +136,7 @@ struct rockchip_drv { * @iomux: array describing the 4 iomux sources of the bank * @drv: array describing the 4 drive strength sources of the bank * @pull_type: array describing the 4 pull type sources of the bank - * @valid: are all necessary informations present + * @valid: is all necessary information present * @of_node: dt node of this bank * @drvdata: common pinctrl basedata * @domain: irqdomain of the gpio bank @@ -1988,7 +1988,7 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, info->functions[selector].name, info->groups[group].name); /* - * for each pin in the pin group selected, program the correspoding pin + * for each pin in the pin group selected, program the corresponding * pin function number in the config register. */ for (cnt = 0; cnt < info->groups[group].npins; cnt++) { @@ -2535,7 +2535,7 @@ static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset) /* * gpiolib gpio_direction_input callback function. The setting of the pin - * mux function as 'gpio input' will be handled by the pinctrl susbsystem + * mux function as 'gpio input' will be handled by the pinctrl subsystem * interface. */ static int rockchip_gpio_direction_input(struct gpio_chip *gc, unsigned offset) @@ -2545,7 +2545,7 @@ static int rockchip_gpio_direction_input(struct gpio_chip *gc, unsigned offset) /* * gpiolib gpio_direction_output callback function. The setting of the pin - * mux function as 'gpio output' will be handled by the pinctrl susbsystem + * mux function as 'gpio output' will be handled by the pinctrl subsystem * interface. */ static int rockchip_gpio_direction_output(struct gpio_chip *gc, -- cgit From a14aa2716bac1d934cce9fa86beb5d7720f1b3dc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 25 Dec 2017 11:27:55 +0100 Subject: pinctrl: single: Delete an error message for a failed memory allocation in pcs_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-single.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 6f95e6a74e72..2b93d8a07687 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1646,10 +1646,9 @@ static int pcs_probe(struct platform_device *pdev) return -EINVAL; pcs = devm_kzalloc(&pdev->dev, sizeof(*pcs), GFP_KERNEL); - if (!pcs) { - dev_err(&pdev->dev, "could not allocate\n"); + if (!pcs) return -ENOMEM; - } + pcs->dev = &pdev->dev; pcs->np = np; raw_spin_lock_init(&pcs->lock); -- cgit From 7598160d7d8e3639173db3e37fe35a643c72ace2 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 25 Dec 2017 11:35:44 +0100 Subject: pinctrl: single: Delete an unnecessary return statement in pcs_irq_chain_handler() The script "checkpatch.pl" pointed information out like the following. WARNING: void function return statements are not generally useful Thus remove such a statement in the affected function. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-single.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 2b93d8a07687..bd423132ff9c 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1459,8 +1459,6 @@ static void pcs_irq_chain_handler(struct irq_desc *desc) pcs_irq_handle(pcs_soc); /* REVISIT: export and add handle_bad_irq(irq, desc)? */ chained_irq_exit(chip, desc); - - return; } static int pcs_irqdomain_map(struct irq_domain *d, unsigned int irq, -- cgit From 8c017679ab772b2f4f1c8fc8c12917cb2e18cab4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 25 Dec 2017 17:55:48 +0100 Subject: pinctrl: tz1090: Delete an error message for a failed memory allocation in two functions Omit an extra message for a memory allocation failure in these functions. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-tz1090.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c index 74d1ffcc2199..2379ce2be365 100644 --- a/drivers/pinctrl/pinctrl-tz1090.c +++ b/drivers/pinctrl/pinctrl-tz1090.c @@ -1082,10 +1082,8 @@ static int add_map_configs(struct device *dev, dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), GFP_KERNEL); - if (!dup_configs) { - dev_err(dev, "kmemdup(configs) failed\n"); + if (!dup_configs) return -ENOMEM; - } (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; (*map)[*num_maps].data.configs.group_or_pin = group; @@ -1946,10 +1944,9 @@ static int tz1090_pinctrl_probe(struct platform_device *pdev) struct resource *res; pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); - if (!pmx) { - dev_err(&pdev->dev, "Can't alloc tz1090_pmx\n"); + if (!pmx) return -ENOMEM; - } + pmx->dev = &pdev->dev; spin_lock_init(&pmx->lock); -- cgit From 405e64a1cdd953f2f0474d2f131757226bcbc401 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 25 Dec 2017 18:28:02 +0100 Subject: pinctrl: tz1090-pdc: Delete an error message for a failed memory allocation in two functions Omit an extra message for a memory allocation failure in these functions. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-tz1090-pdc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c index 5cfa93cecf73..b16d1c96b7eb 100644 --- a/drivers/pinctrl/pinctrl-tz1090-pdc.c +++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c @@ -357,10 +357,8 @@ static int add_map_configs(struct device *dev, dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), GFP_KERNEL); - if (!dup_configs) { - dev_err(dev, "kmemdup(configs) failed\n"); + if (!dup_configs) return -ENOMEM; - } /* * We support both pins and pin groups, but we need to figure out which @@ -931,10 +929,9 @@ static int tz1090_pdc_pinctrl_probe(struct platform_device *pdev) struct resource *res; pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); - if (!pmx) { - dev_err(&pdev->dev, "Can't alloc tz1090_pdc_pmx\n"); + if (!pmx) return -ENOMEM; - } + pmx->dev = &pdev->dev; spin_lock_init(&pmx->lock); -- cgit From 86f75c65ffc028df28e6b5a6f6574a5beea97310 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 25 Dec 2017 20:04:05 +0100 Subject: pinctrl: utils: Delete an error message for a failed memory allocation in pinctrl_utils_add_map_configs() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-utils.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-utils.c b/drivers/pinctrl/pinctrl-utils.c index 9189fbafb102..f2bcbf62c03d 100644 --- a/drivers/pinctrl/pinctrl-utils.c +++ b/drivers/pinctrl/pinctrl-utils.c @@ -83,10 +83,8 @@ int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev, dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), GFP_KERNEL); - if (!dup_configs) { - dev_err(pctldev->dev, "kmemdup(configs) failed\n"); + if (!dup_configs) return -ENOMEM; - } (*map)[*num_maps].type = type; (*map)[*num_maps].data.configs.group_or_pin = group; -- cgit From e423f0ceef436b3246fd8b0d5ed51cf89fd8b45e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 25 Dec 2017 21:51:26 +0100 Subject: pinctrl: xway: Delete two error messages for a failed memory allocation in pinmux_xway_probe() Omit extra messages for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-xway.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index f9e98a7d4f0c..cd0f402c1164 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -1730,18 +1730,16 @@ static int pinmux_xway_probe(struct platform_device *pdev) xway_info.pads = devm_kzalloc(&pdev->dev, sizeof(struct pinctrl_pin_desc) * xway_chip.ngpio, GFP_KERNEL); - if (!xway_info.pads) { - dev_err(&pdev->dev, "Failed to allocate pads\n"); + if (!xway_info.pads) return -ENOMEM; - } + for (i = 0; i < xway_chip.ngpio; i++) { /* strlen("ioXY") + 1 = 5 */ char *name = devm_kzalloc(&pdev->dev, 5, GFP_KERNEL); - if (!name) { - dev_err(&pdev->dev, "Failed to allocate pad name\n"); + if (!name) return -ENOMEM; - } + snprintf(name, 5, "io%d", i); xway_info.pads[i].number = GPIO0 + i; xway_info.pads[i].name = name; -- cgit From 221173a3fc2063247a07d7f523704634d17112fb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 26 Dec 2017 19:09:42 +0100 Subject: pinctrl: samsung: Add SPDX license identifiers Replace GPL license statements with SPDX GPL-2.0+ license identifiers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/pinctrl/samsung/Kconfig | 1 + drivers/pinctrl/samsung/pinctrl-exynos-arm.c | 33 ++++++++++------------- drivers/pinctrl/samsung/pinctrl-exynos-arm64.c | 33 ++++++++++------------- drivers/pinctrl/samsung/pinctrl-exynos.c | 33 ++++++++++------------- drivers/pinctrl/samsung/pinctrl-exynos.h | 6 +---- drivers/pinctrl/samsung/pinctrl-exynos5440.c | 21 ++++++--------- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 23 +++++++--------- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 27 ++++++++----------- drivers/pinctrl/samsung/pinctrl-samsung.c | 37 +++++++++++--------------- drivers/pinctrl/samsung/pinctrl-samsung.h | 6 +---- 10 files changed, 89 insertions(+), 131 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/Kconfig b/drivers/pinctrl/samsung/Kconfig index ecfb90059eeb..11b5eeb14c4a 100644 --- a/drivers/pinctrl/samsung/Kconfig +++ b/drivers/pinctrl/samsung/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Samsung Pin control drivers # diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm.c index 071084d3ee9c..c32399faff57 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm.c @@ -1,22 +1,17 @@ -/* - * Exynos specific support for Samsung pinctrl/gpiolib driver with eint support. - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Copyright (c) 2012 Linaro Ltd - * http://www.linaro.org - * - * Author: Thomas Abraham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This file contains the Samsung Exynos specific information required by the - * the Samsung pinctrl/gpiolib driver. It also includes the implementation of - * external gpio and wakeup interrupt support. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Exynos specific support for Samsung pinctrl/gpiolib driver with eint support. +// +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// Copyright (c) 2012 Linaro Ltd +// http://www.linaro.org +// +// Author: Thomas Abraham +// +// This file contains the Samsung Exynos specific information required by the +// the Samsung pinctrl/gpiolib driver. It also includes the implementation of +// external gpio and wakeup interrupt support. #include #include diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c index 08e9fdb58fd2..fc8f7833bec0 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -1,22 +1,17 @@ -/* - * Exynos ARMv8 specific support for Samsung pinctrl/gpiolib driver - * with eint support. - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Copyright (c) 2012 Linaro Ltd - * http://www.linaro.org - * Copyright (c) 2017 Krzysztof Kozlowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This file contains the Samsung Exynos specific information required by the - * the Samsung pinctrl/gpiolib driver. It also includes the implementation of - * external gpio and wakeup interrupt support. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Exynos ARMv8 specific support for Samsung pinctrl/gpiolib driver +// with eint support. +// +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// Copyright (c) 2012 Linaro Ltd +// http://www.linaro.org +// Copyright (c) 2017 Krzysztof Kozlowski +// +// This file contains the Samsung Exynos specific information required by the +// the Samsung pinctrl/gpiolib driver. It also includes the implementation of +// external gpio and wakeup interrupt support. #include #include diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index c8d0de7ea160..0a625a64ff5d 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -1,22 +1,17 @@ -/* - * Exynos specific support for Samsung pinctrl/gpiolib driver with eint support. - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Copyright (c) 2012 Linaro Ltd - * http://www.linaro.org - * - * Author: Thomas Abraham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This file contains the Samsung Exynos specific information required by the - * the Samsung pinctrl/gpiolib driver. It also includes the implementation of - * external gpio and wakeup interrupt support. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Exynos specific support for Samsung pinctrl/gpiolib driver with eint support. +// +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// Copyright (c) 2012 Linaro Ltd +// http://www.linaro.org +// +// Author: Thomas Abraham +// +// This file contains the Samsung Exynos specific information required by the +// the Samsung pinctrl/gpiolib driver. It also includes the implementation of +// external gpio and wakeup interrupt support. #include #include diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 7639b926c5c1..abd43aa7eb0d 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Exynos specific definitions for Samsung pinctrl and gpiolib driver. * @@ -10,11 +11,6 @@ * pinctrl/gpiolib interface drivers. * * Author: Thomas Abraham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #ifndef __PINCTRL_SAMSUNG_EXYNOS_H diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index 32a3a9fd65c4..3d8d5e812839 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -1,16 +1,11 @@ -/* - * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC. - * - * Author: Thomas Abraham - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC. +// +// Author: Thomas Abraham +// +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// http://www.samsung.com #include #include diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index edf27264b603..10187cb0e9b9 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -1,17 +1,12 @@ -/* - * S3C24XX specific support for Samsung pinctrl/gpiolib driver. - * - * Copyright (c) 2013 Heiko Stuebner - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This file contains the SamsungS3C24XX specific information required by the - * Samsung pinctrl/gpiolib driver. It also includes the implementation of - * external gpio and wakeup interrupt support. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// S3C24XX specific support for Samsung pinctrl/gpiolib driver. +// +// Copyright (c) 2013 Heiko Stuebner +// +// This file contains the SamsungS3C24XX specific information required by the +// Samsung pinctrl/gpiolib driver. It also includes the implementation of +// external gpio and wakeup interrupt support. #include #include diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index e63663b32907..679628ac4b31 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -1,19 +1,14 @@ -/* - * S3C64xx specific support for pinctrl-samsung driver. - * - * Copyright (c) 2013 Tomasz Figa - * - * Based on pinctrl-exynos.c, please see the file for original copyrights. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This file contains the Samsung S3C64xx specific information required by the - * the Samsung pinctrl/gpiolib driver. It also includes the implementation of - * external gpio and wakeup interrupt support. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// S3C64xx specific support for pinctrl-samsung driver. +// +// Copyright (c) 2013 Tomasz Figa +// +// Based on pinctrl-exynos.c, please see the file for original copyrights. +// +// This file contains the Samsung S3C64xx specific information required by the +// the Samsung pinctrl/gpiolib driver. It also includes the implementation of +// external gpio and wakeup interrupt support. #include #include diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index e04f7fe0a65d..da58e4554137 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1,24 +1,19 @@ -/* - * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Copyright (c) 2012 Linaro Ltd - * http://www.linaro.org - * - * Author: Thomas Abraham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver implements the Samsung pinctrl driver. It supports setting up of - * pinmux and pinconf configurations. The gpiolib interface is also included. - * External interrupt (gpio and wakeup) support are not included in this driver - * but provides extensions to which platform specific implementation of the gpio - * and wakeup interrupts can be hooked to. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. +// +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// Copyright (c) 2012 Linaro Ltd +// http://www.linaro.org +// +// Author: Thomas Abraham +// +// This driver implements the Samsung pinctrl driver. It supports setting up of +// pinmux and pinconf configurations. The gpiolib interface is also included. +// External interrupt (gpio and wakeup) support are not included in this driver +// but provides extensions to which platform specific implementation of the gpio +// and wakeup interrupts can be hooked to. #include #include diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 9af07af6cad6..e204f609823b 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. * @@ -7,11 +8,6 @@ * http://www.linaro.org * * Author: Thomas Abraham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #ifndef __PINCTRL_SAMSUNG_H -- cgit From b5623acb8d826545046184fab31049d6cd1deb83 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 27 Dec 2017 22:34:28 +0100 Subject: pinctrl/spear/plgpio: Delete two error messages for a failed memory allocation in plgpio_probe() Omit extra messages for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/pinctrl/spear/pinctrl-plgpio.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c index 6a0ed8ab33b9..d2123e396b29 100644 --- a/drivers/pinctrl/spear/pinctrl-plgpio.c +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -519,10 +519,8 @@ static int plgpio_probe(struct platform_device *pdev) int ret, irq; plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL); - if (!plgpio) { - dev_err(&pdev->dev, "memory allocation fail\n"); + if (!plgpio) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); plgpio->base = devm_ioremap_resource(&pdev->dev, res); @@ -544,10 +542,8 @@ static int plgpio_probe(struct platform_device *pdev) sizeof(*plgpio->csave_regs) * DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG), GFP_KERNEL); - if (!plgpio->csave_regs) { - dev_err(&pdev->dev, "csave registers memory allocation fail\n"); + if (!plgpio->csave_regs) return -ENOMEM; - } #endif platform_set_drvdata(pdev, plgpio); -- cgit From 51d7a036a6b0b3b64aeb4441d71e238ef6fb4a22 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 27 Dec 2017 22:44:04 +0100 Subject: pinctrl: spear: Delete an error message for a failed memory allocation in spear_pinctrl_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/pinctrl/spear/pinctrl-spear.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index 4db52ba38d8d..efe79d3f7659 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -361,10 +361,8 @@ int spear_pinctrl_probe(struct platform_device *pdev, return -ENODEV; pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); - if (!pmx) { - dev_err(&pdev->dev, "Can't alloc spear_pmx\n"); + if (!pmx) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pmx->vbase = devm_ioremap_resource(&pdev->dev, res); -- cgit From b18b2e775934470e154e68799946bd85e48a77fa Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 28 Dec 2017 15:15:08 +0100 Subject: pinctrl: tegra: Delete two error messages for a failed memory allocation in tegra_pinctrl_probe() Omit extra messages for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/tegra/pinctrl-tegra.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index 51716819129d..72c718e66ebb 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -666,10 +666,9 @@ int tegra_pinctrl_probe(struct platform_device *pdev, int fn, gn, gfn; pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); - if (!pmx) { - dev_err(&pdev->dev, "Can't alloc tegra_pmx\n"); + if (!pmx) return -ENOMEM; - } + pmx->dev = &pdev->dev; pmx->soc = soc_data; @@ -722,10 +721,8 @@ int tegra_pinctrl_probe(struct platform_device *pdev, pmx->regs = devm_kzalloc(&pdev->dev, pmx->nbanks * sizeof(*pmx->regs), GFP_KERNEL); - if (!pmx->regs) { - dev_err(&pdev->dev, "Can't alloc regs pointer\n"); + if (!pmx->regs) return -ENOMEM; - } for (i = 0; i < pmx->nbanks; i++) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); -- cgit From 5a10e7d7aafd01dd4310185b2de3c3a7e2fcf06e Mon Sep 17 00:00:00 2001 From: Jun Gao Date: Tue, 19 Dec 2017 14:51:02 +0800 Subject: i2c: mediatek: Add i2c compatible for MediaTek MT2712 Add i2c compatible for MT2712. Compare to MT8173 i2c controller, internal divider of i2c source clock need to be configured for MT2712 i2c speed calculation. Signed-off-by: Jun Gao Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mt65xx.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 09d288ce0ddb..58d6401871a9 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -61,6 +61,7 @@ #define I2C_DMA_HARD_RST 0x0002 #define I2C_DMA_4G_MODE 0x0001 +#define I2C_DEFAULT_CLK_DIV 5 #define I2C_DEFAULT_SPEED 100000 /* hz */ #define MAX_FS_MODE_SPEED 400000 #define MAX_HS_MODE_SPEED 3400000 @@ -127,6 +128,7 @@ enum I2C_REGS_OFFSET { OFFSET_DEBUGSTAT = 0x64, OFFSET_DEBUGCTRL = 0x68, OFFSET_TRANSFER_LEN_AUX = 0x6c, + OFFSET_CLOCK_DIV = 0x70, }; struct mtk_i2c_compatible { @@ -136,6 +138,7 @@ struct mtk_i2c_compatible { unsigned char auto_restart: 1; unsigned char aux_len_reg: 1; unsigned char support_33bits: 1; + unsigned char timing_adjust: 1; }; struct mtk_i2c { @@ -176,6 +179,15 @@ static const struct i2c_adapter_quirks mt7622_i2c_quirks = { .max_num_msgs = 255, }; +static const struct mtk_i2c_compatible mt2712_compat = { + .pmic_i2c = 0, + .dcm = 1, + .auto_restart = 1, + .aux_len_reg = 1, + .support_33bits = 1, + .timing_adjust = 1, +}; + static const struct mtk_i2c_compatible mt6577_compat = { .quirks = &mt6577_i2c_quirks, .pmic_i2c = 0, @@ -183,6 +195,7 @@ static const struct mtk_i2c_compatible mt6577_compat = { .auto_restart = 0, .aux_len_reg = 0, .support_33bits = 0, + .timing_adjust = 0, }; static const struct mtk_i2c_compatible mt6589_compat = { @@ -192,6 +205,7 @@ static const struct mtk_i2c_compatible mt6589_compat = { .auto_restart = 0, .aux_len_reg = 0, .support_33bits = 0, + .timing_adjust = 0, }; static const struct mtk_i2c_compatible mt7622_compat = { @@ -201,6 +215,7 @@ static const struct mtk_i2c_compatible mt7622_compat = { .auto_restart = 1, .aux_len_reg = 1, .support_33bits = 0, + .timing_adjust = 0, }; static const struct mtk_i2c_compatible mt8173_compat = { @@ -209,9 +224,11 @@ static const struct mtk_i2c_compatible mt8173_compat = { .auto_restart = 1, .aux_len_reg = 1, .support_33bits = 1, + .timing_adjust = 0, }; static const struct of_device_id mtk_i2c_of_match[] = { + { .compatible = "mediatek,mt2712-i2c", .data = &mt2712_compat }, { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat }, { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat }, { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat }, @@ -271,6 +288,9 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c) if (i2c->dev_comp->dcm) writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN); + if (i2c->dev_comp->timing_adjust) + writew(I2C_DEFAULT_CLK_DIV - 1, i2c->base + OFFSET_CLOCK_DIV); + writew(i2c->timing_reg, i2c->base + OFFSET_TIMING); writew(i2c->high_speed_reg, i2c->base + OFFSET_HS); @@ -725,10 +745,6 @@ static int mtk_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c); - if (ret) - return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(i2c->base)) @@ -759,6 +775,13 @@ static int mtk_i2c_probe(struct platform_device *pdev) i2c->adap.timeout = 2 * HZ; i2c->adap.retries = 1; + ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c); + if (ret) + return -EINVAL; + + if (i2c->dev_comp->timing_adjust) + i2c->clk_src_div *= I2C_DEFAULT_CLK_DIV; + if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c) return -EINVAL; -- cgit From f6762cedbef91ad1da338538efa811856a717d57 Mon Sep 17 00:00:00 2001 From: Jun Gao Date: Tue, 19 Dec 2017 14:51:03 +0800 Subject: i2c: mediatek: Enable i2c module clock before i2c registers access. Make sure i2c module clock has been enabled before i2c registers access. Signed-off-by: Jun Gao Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mt65xx.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 58d6401871a9..cf23a746cc17 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -861,10 +861,19 @@ static int mtk_i2c_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int mtk_i2c_resume(struct device *dev) { + int ret; struct mtk_i2c *i2c = dev_get_drvdata(dev); + ret = mtk_i2c_clock_enable(i2c); + if (ret) { + dev_err(dev, "clock enable failed!\n"); + return ret; + } + mtk_i2c_init_hw(i2c); + mtk_i2c_clock_disable(i2c); + return 0; } #endif -- cgit From f11a04464ae57e8db1bb7634547842b43e36a898 Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Fri, 22 Dec 2017 22:47:16 +0100 Subject: i2c: gpio: Enable working over slow can_sleep GPIOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Slow" GPIOs (usually those connected over an SPI or an I2C bus) are, well, slow in their operation. It is generally a good idea to avoid using them for time-critical operation, but sometimes the hardware just sucks, and the software has to cope. In addition to that, the I2C bus itself does not actually define any strict timing limits; the bus is free to go all the way down to DC. The timeouts (and therefore the slowest acceptable frequency) are present only in SMBus. The `can_sleep` is IMHO a wrong concept to use here. My SPI-to-quad-UART chip (MAX14830) is connected via a 26MHz SPI bus, and it happily drives SCL at 200kHz (5µs pulses) during my benchmarks. That's faster than the maximal allowed speed of the traditional I2C. The previous version of this code did not really block operation over slow GPIO pins, anyway. Instead, it just resorted to printing a warning with a backtrace each time a GPIO pin was accessed, thereby slowing things down even more. Finally, it's not just me. A similar patch was originally submitted in 2015 [1]. [1] https://patchwork.ozlabs.org/patch/450956/ Signed-off-by: Jan Kundrát Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-gpio.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 3312ef981cb7..58abb3eced58 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -39,7 +39,7 @@ static void i2c_gpio_setsda_val(void *data, int state) { struct i2c_gpio_private_data *priv = data; - gpiod_set_value(priv->sda, state); + gpiod_set_value_cansleep(priv->sda, state); } /* @@ -52,21 +52,21 @@ static void i2c_gpio_setscl_val(void *data, int state) { struct i2c_gpio_private_data *priv = data; - gpiod_set_value(priv->scl, state); + gpiod_set_value_cansleep(priv->scl, state); } static int i2c_gpio_getsda(void *data) { struct i2c_gpio_private_data *priv = data; - return gpiod_get_value(priv->sda); + return gpiod_get_value_cansleep(priv->sda); } static int i2c_gpio_getscl(void *data) { struct i2c_gpio_private_data *priv = data; - return gpiod_get_value(priv->scl); + return gpiod_get_value_cansleep(priv->scl); } #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR @@ -286,6 +286,9 @@ static int i2c_gpio_probe(struct platform_device *pdev) if (IS_ERR(priv->scl)) return PTR_ERR(priv->scl); + if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) + dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); + bit_data->setsda = i2c_gpio_setsda_val; bit_data->setscl = i2c_gpio_setscl_val; -- cgit From 659e7142bd91a2054368f281801f8c47633e4487 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 28 Dec 2017 16:12:17 +0100 Subject: pinctrl: vt8500: Delete an error message for a failed memory allocation in five functions Omit an extra message for a memory allocation failure in these functions. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/vt8500/pinctrl-vt8500.c | 4 +--- drivers/pinctrl/vt8500/pinctrl-wm8505.c | 4 +--- drivers/pinctrl/vt8500/pinctrl-wm8650.c | 4 +--- drivers/pinctrl/vt8500/pinctrl-wm8750.c | 4 +--- drivers/pinctrl/vt8500/pinctrl-wm8850.c | 4 +--- 5 files changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/vt8500/pinctrl-vt8500.c b/drivers/pinctrl/vt8500/pinctrl-vt8500.c index 767f340d6b11..9086a3758eee 100644 --- a/drivers/pinctrl/vt8500/pinctrl-vt8500.c +++ b/drivers/pinctrl/vt8500/pinctrl-vt8500.c @@ -458,10 +458,8 @@ static int vt8500_pinctrl_probe(struct platform_device *pdev) struct wmt_pinctrl_data *data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate data\n"); + if (!data) return -ENOMEM; - } data->banks = vt8500_banks; data->nbanks = ARRAY_SIZE(vt8500_banks); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8505.c b/drivers/pinctrl/vt8500/pinctrl-wm8505.c index a56fdbd87e42..e1aae1d4b0b1 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wm8505.c +++ b/drivers/pinctrl/vt8500/pinctrl-wm8505.c @@ -489,10 +489,8 @@ static int wm8505_pinctrl_probe(struct platform_device *pdev) struct wmt_pinctrl_data *data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate data\n"); + if (!data) return -ENOMEM; - } data->banks = wm8505_banks; data->nbanks = ARRAY_SIZE(wm8505_banks); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8650.c b/drivers/pinctrl/vt8500/pinctrl-wm8650.c index 270dd491f5a1..4678227d4001 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wm8650.c +++ b/drivers/pinctrl/vt8500/pinctrl-wm8650.c @@ -327,10 +327,8 @@ static int wm8650_pinctrl_probe(struct platform_device *pdev) struct wmt_pinctrl_data *data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate data\n"); + if (!data) return -ENOMEM; - } data->banks = wm8650_banks; data->nbanks = ARRAY_SIZE(wm8650_banks); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8750.c b/drivers/pinctrl/vt8500/pinctrl-wm8750.c index 74f7b3a18f3a..c46d6946c8f5 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wm8750.c +++ b/drivers/pinctrl/vt8500/pinctrl-wm8750.c @@ -366,10 +366,8 @@ static int wm8750_pinctrl_probe(struct platform_device *pdev) struct wmt_pinctrl_data *data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate data\n"); + if (!data) return -ENOMEM; - } data->banks = wm8750_banks; data->nbanks = ARRAY_SIZE(wm8750_banks); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8850.c b/drivers/pinctrl/vt8500/pinctrl-wm8850.c index 45792aa7a06e..e2e85316a65e 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wm8850.c +++ b/drivers/pinctrl/vt8500/pinctrl-wm8850.c @@ -345,10 +345,8 @@ static int wm8850_pinctrl_probe(struct platform_device *pdev) struct wmt_pinctrl_data *data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate data\n"); + if (!data) return -ENOMEM; - } data->banks = wm8850_banks; data->nbanks = ARRAY_SIZE(wm8850_banks); -- cgit From 9291c65b01d1c67ebd56644cb19317ad665c44b3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 1 Jan 2018 13:23:57 +0100 Subject: pinctrl: baytrail: Enable glitch filter for GPIOs used as interrupts On some systems, some PCB traces attached to GpioInts are routed in such a way that they pick up enough interference to constantly (many times per second) trigger. Enabling glitch-filtering fixes this. Signed-off-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-baytrail.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 9c1ca29c60b7..6b52ea1440a6 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -46,6 +46,9 @@ #define BYT_TRIG_POS BIT(25) #define BYT_TRIG_LVL BIT(24) #define BYT_DEBOUNCE_EN BIT(20) +#define BYT_GLITCH_FILTER_EN BIT(19) +#define BYT_GLITCH_F_SLOW_CLK BIT(17) +#define BYT_GLITCH_F_FAST_CLK BIT(16) #define BYT_PULL_STR_SHIFT 9 #define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT) #define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT) @@ -1579,6 +1582,9 @@ static int byt_irq_type(struct irq_data *d, unsigned int type) */ value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + /* Enable glitch filtering */ + value |= BYT_GLITCH_FILTER_EN | BYT_GLITCH_F_SLOW_CLK | + BYT_GLITCH_F_FAST_CLK; writel(value, reg); -- cgit From 8b74c7d3e30fdd3f2c083d3becae7be6cd38989f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 2 Jan 2018 14:27:58 +0100 Subject: pinctrl: at91-pio4: account for const type of of_device_id.data This driver creates a const structure that it stores in the data field of an of_device_id array. Adding const to the declaration of the location that receives the const value from the data field ensures that the compiler will continue to check that the value is not modified. Furthermore, the const-discarding cast on the extraction from the data field is no longer needed. Done using Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91-pio4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index b1ca838dd80a..4b57a13758a4 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -910,7 +910,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) int i, ret; struct resource *res; struct atmel_pioctrl *atmel_pioctrl; - struct atmel_pioctrl_data *atmel_pioctrl_data; + const struct atmel_pioctrl_data *atmel_pioctrl_data; atmel_pioctrl = devm_kzalloc(dev, sizeof(*atmel_pioctrl), GFP_KERNEL); if (!atmel_pioctrl) @@ -924,7 +924,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) dev_err(dev, "unknown compatible string\n"); return -ENODEV; } - atmel_pioctrl_data = (struct atmel_pioctrl_data *)match->data; + atmel_pioctrl_data = match->data; atmel_pioctrl->nbanks = atmel_pioctrl_data->nbanks; atmel_pioctrl->npins = atmel_pioctrl->nbanks * ATMEL_PIO_NPINS_PER_BANK; -- cgit From 9b8ee3c0f6b27f9fb5dbc382afa7ef1f05fed491 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 2 Jan 2018 14:28:04 +0100 Subject: pinctrl: axp209: account for const type of of_device_id.data The return value of of_device_get_match_data has type const void *. The desc field of the pctl structure also has a const type, so there is no need for the const-discarding cast between them. Done using Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-axp209.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index 510a2821e910..1231bbbfa744 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -414,7 +414,7 @@ static int axp20x_pctl_probe(struct platform_device *pdev) pctl->chip.direction_input = axp20x_gpio_input; pctl->chip.direction_output = axp20x_gpio_output; - pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); + pctl->desc = of_device_get_match_data(dev); pctl->chip.ngpio = pctl->desc->npins; -- cgit From 924f5494da610664cc5a9fccc12d32fbbc6214d3 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 2 Jan 2018 14:28:01 +0100 Subject: pinctrl: armada-37xx: account for const type of of_device_id.data The data field of an of_device_id structure has type const void *, so there is no need for a const-discarding cast when putting const values into such a structure. Done using Coccinelle. Signed-off-by: Julia Lawall Acked-by: Gregory CLEMENT Signed-off-by: Linus Walleij --- drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index d45af31b86b4..7edebd1e8c29 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -997,11 +997,11 @@ static int armada_37xx_pinctrl_register(struct platform_device *pdev, static const struct of_device_id armada_37xx_pinctrl_of_match[] = { { .compatible = "marvell,armada3710-sb-pinctrl", - .data = (void *)&armada_37xx_pin_sb, + .data = &armada_37xx_pin_sb, }, { .compatible = "marvell,armada3710-nb-pinctrl", - .data = (void *)&armada_37xx_pin_nb, + .data = &armada_37xx_pin_nb, }, { }, }; -- cgit From 2ee4e9ce594b7c4dae5102fa86ce6339b98a4bc8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 5 Dec 2017 16:57:53 -0800 Subject: scsi: scsi-mq-debugfs: Show more information Show the request result, request timeout and SCSI command flags. This information is very helpful when trying to figure out why a queue got stuck. An example of the information that is exported through debugfs: $ (cd /sys/kernel/debug/block && find -type f -print0 | xargs -0 grep ago) ./sda/hctx0/busy:ffff8804a4523300 {.op=READ, .cmd_flags=FAILFAST_DEV|FAILFAST_TRANSPORT|FAILFAST_DRIVER|RAHEAD, .rq_flags=MQ_INFLIGHT|DONTPREP|IO_STAT|STATS, .atomic_flags=STARTED, .tag=24, .internal_tag=-1, .cmd=Read(10) 28 00 06 80 1c c8 00 00 08 00, .retries=0, .result = 0x0, .flags=TAGGED|INITIALIZED, .timeout=90.000, allocated 0.010 s ago} Signed-off-by: Bart Van Assche Cc: James E.J. Bottomley Cc: Martin K. Petersen Cc: Ming Lei Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debugfs.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_debugfs.c b/drivers/scsi/scsi_debugfs.c index c3765d29fd3f..37ed6bb8e6ec 100644 --- a/drivers/scsi/scsi_debugfs.c +++ b/drivers/scsi/scsi_debugfs.c @@ -4,15 +4,50 @@ #include #include "scsi_debugfs.h" +#define SCSI_CMD_FLAG_NAME(name) [ilog2(SCMD_##name)] = #name +static const char *const scsi_cmd_flags[] = { + SCSI_CMD_FLAG_NAME(TAGGED), + SCSI_CMD_FLAG_NAME(UNCHECKED_ISA_DMA), + SCSI_CMD_FLAG_NAME(ZONE_WRITE_LOCK), + SCSI_CMD_FLAG_NAME(INITIALIZED), +}; +#undef SCSI_CMD_FLAG_NAME + +static int scsi_flags_show(struct seq_file *m, const unsigned long flags, + const char *const *flag_name, int flag_name_count) +{ + bool sep = false; + int i; + + for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) { + if (!(flags & BIT(i))) + continue; + if (sep) + seq_puts(m, "|"); + sep = true; + if (i < flag_name_count && flag_name[i]) + seq_puts(m, flag_name[i]); + else + seq_printf(m, "%d", i); + } + return 0; +} + void scsi_show_rq(struct seq_file *m, struct request *rq) { struct scsi_cmnd *cmd = container_of(scsi_req(rq), typeof(*cmd), req); - int msecs = jiffies_to_msecs(jiffies - cmd->jiffies_at_alloc); + int alloc_ms = jiffies_to_msecs(jiffies - cmd->jiffies_at_alloc); + int timeout_ms = jiffies_to_msecs(rq->timeout); const u8 *const cdb = READ_ONCE(cmd->cmnd); char buf[80] = "(?)"; if (cdb) __scsi_format_command(buf, sizeof(buf), cdb, cmd->cmd_len); - seq_printf(m, ", .cmd=%s, .retries=%d, allocated %d.%03d s ago", buf, - cmd->retries, msecs / 1000, msecs % 1000); + seq_printf(m, ", .cmd=%s, .retries=%d, .result = %#x, .flags=", buf, + cmd->retries, cmd->result); + scsi_flags_show(m, cmd->flags, scsi_cmd_flags, + ARRAY_SIZE(scsi_cmd_flags)); + seq_printf(m, ", .timeout=%d.%03d, allocated %d.%03d s ago", + timeout_ms / 1000, timeout_ms % 1000, + alloc_ms / 1000, alloc_ms % 1000); } -- cgit From 23349ca93aed05917d9178d0a9e21db599a0eb5d Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 21 Dec 2017 15:43:43 +0900 Subject: scsi: sd_zbc: Initialize device request queue zoned data Initialize the seq_zones_bitmap, seq_zones_wlock and nr_zones fields of the disk request queue on disk revalidate. As the seq_zones_bitmap and seq_zones_wlock allocations are identical, introduce the helper sd_zbc_alloc_zone_bitmap(). Using this helper, reallocate the bitmaps whenever the disk capacity (number of zones) changes. Signed-off-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/sd_zbc.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 144 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 27793b9f54c0..c715b8363ce0 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -586,8 +586,123 @@ out: return 0; } +/** + * sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap (one bit per zone). + * @sdkp: The disk of the bitmap + */ +static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + + return kzalloc_node(BITS_TO_LONGS(sdkp->nr_zones) + * sizeof(unsigned long), + GFP_KERNEL, q->node); +} + +/** + * sd_zbc_get_seq_zones - Parse report zones reply to identify sequential zones + * @sdkp: disk used + * @buf: report reply buffer + * @seq_zone_bitamp: bitmap of sequential zones to set + * + * Parse reported zone descriptors in @buf to identify sequential zones and + * set the reported zone bit in @seq_zones_bitmap accordingly. + * Since read-only and offline zones cannot be written, do not + * mark them as sequential in the bitmap. + * Return the LBA after the last zone reported. + */ +static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf, + unsigned int buflen, + unsigned long *seq_zones_bitmap) +{ + sector_t lba, next_lba = sdkp->capacity; + unsigned int buf_len, list_length; + unsigned char *rec; + u8 type, cond; + + list_length = get_unaligned_be32(&buf[0]) + 64; + buf_len = min(list_length, buflen); + rec = buf + 64; + + while (rec < buf + buf_len) { + type = rec[0] & 0x0f; + cond = (rec[1] >> 4) & 0xf; + lba = get_unaligned_be64(&rec[16]); + if (type != ZBC_ZONE_TYPE_CONV && + cond != ZBC_ZONE_COND_READONLY && + cond != ZBC_ZONE_COND_OFFLINE) + set_bit(lba >> sdkp->zone_shift, seq_zones_bitmap); + next_lba = lba + get_unaligned_be64(&rec[8]); + rec += 64; + } + + return next_lba; +} + +/** + * sd_zbc_setup_seq_zones_bitmap - Initialize the disk seq zone bitmap. + * @sdkp: target disk + * + * Allocate a zone bitmap and initialize it by identifying sequential zones. + */ +static int sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + unsigned long *seq_zones_bitmap; + sector_t lba = 0; + unsigned char *buf; + int ret = -ENOMEM; + + seq_zones_bitmap = sd_zbc_alloc_zone_bitmap(sdkp); + if (!seq_zones_bitmap) + return -ENOMEM; + + buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); + if (!buf) + goto out; + + while (lba < sdkp->capacity) { + ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba); + if (ret) + goto out; + lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE, + seq_zones_bitmap); + } + + if (lba != sdkp->capacity) { + /* Something went wrong */ + ret = -EIO; + } + +out: + kfree(buf); + if (ret) { + kfree(seq_zones_bitmap); + return ret; + } + + q->seq_zones_bitmap = seq_zones_bitmap; + + return 0; +} + +static void sd_zbc_cleanup(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + + kfree(q->seq_zones_bitmap); + q->seq_zones_bitmap = NULL; + + kfree(q->seq_zones_wlock); + q->seq_zones_wlock = NULL; + + q->nr_zones = 0; +} + static int sd_zbc_setup(struct scsi_disk *sdkp) { + struct request_queue *q = sdkp->disk->queue; + int ret; /* READ16/WRITE16 is mandatory for ZBC disks */ sdkp->device->use_16_for_rw = 1; @@ -599,15 +714,36 @@ static int sd_zbc_setup(struct scsi_disk *sdkp) sdkp->nr_zones = round_up(sdkp->capacity, sdkp->zone_blocks) >> sdkp->zone_shift; - if (!sdkp->zones_wlock) { - sdkp->zones_wlock = kcalloc(BITS_TO_LONGS(sdkp->nr_zones), - sizeof(unsigned long), - GFP_KERNEL); - if (!sdkp->zones_wlock) - return -ENOMEM; + /* + * Initialize the device request queue information if the number + * of zones changed. + */ + if (sdkp->nr_zones != q->nr_zones) { + + sd_zbc_cleanup(sdkp); + + q->nr_zones = sdkp->nr_zones; + if (sdkp->nr_zones) { + q->seq_zones_wlock = sd_zbc_alloc_zone_bitmap(sdkp); + if (!q->seq_zones_wlock) { + ret = -ENOMEM; + goto err; + } + + ret = sd_zbc_setup_seq_zones_bitmap(sdkp); + if (ret) { + sd_zbc_cleanup(sdkp); + goto err; + } + } + } return 0; + +err: + sd_zbc_cleanup(sdkp); + return ret; } int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) @@ -661,14 +797,14 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) err: sdkp->capacity = 0; + sd_zbc_cleanup(sdkp); return ret; } void sd_zbc_remove(struct scsi_disk *sdkp) { - kfree(sdkp->zones_wlock); - sdkp->zones_wlock = NULL; + sd_zbc_cleanup(sdkp); } void sd_zbc_print_zones(struct scsi_disk *sdkp) -- cgit From 39051dd85f2870624c3fc7a099b11c67fb822aed Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 21 Dec 2017 15:43:44 +0900 Subject: scsi: sd: Remove zone write locking The block layer now handles zone write locking. [mkp: removed SCMD_ZONE_WRITE_LOCK reference in scsi_debugfs] Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debugfs.c | 1 - drivers/scsi/sd.c | 41 +++------------------- drivers/scsi/sd.h | 11 ------ drivers/scsi/sd_zbc.c | 83 --------------------------------------------- 4 files changed, 5 insertions(+), 131 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_debugfs.c b/drivers/scsi/scsi_debugfs.c index 37ed6bb8e6ec..b784002ef0bd 100644 --- a/drivers/scsi/scsi_debugfs.c +++ b/drivers/scsi/scsi_debugfs.c @@ -8,7 +8,6 @@ static const char *const scsi_cmd_flags[] = { SCSI_CMD_FLAG_NAME(TAGGED), SCSI_CMD_FLAG_NAME(UNCHECKED_ISA_DMA), - SCSI_CMD_FLAG_NAME(ZONE_WRITE_LOCK), SCSI_CMD_FLAG_NAME(INITIALIZED), }; #undef SCSI_CMD_FLAG_NAME diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a028ab3322a9..f1157b4fe32e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -851,16 +851,13 @@ static int sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); u64 sector = blk_rq_pos(rq) >> (ilog2(sdp->sector_size) - 9); u32 nr_sectors = blk_rq_sectors(rq) >> (ilog2(sdp->sector_size) - 9); - int ret; if (!(rq->cmd_flags & REQ_NOUNMAP)) { switch (sdkp->zeroing_mode) { case SD_ZERO_WS16_UNMAP: - ret = sd_setup_write_same16_cmnd(cmd, true); - goto out; + return sd_setup_write_same16_cmnd(cmd, true); case SD_ZERO_WS10_UNMAP: - ret = sd_setup_write_same10_cmnd(cmd, true); - goto out; + return sd_setup_write_same10_cmnd(cmd, true); } } @@ -868,15 +865,9 @@ static int sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) return BLKPREP_INVALID; if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff) - ret = sd_setup_write_same16_cmnd(cmd, false); - else - ret = sd_setup_write_same10_cmnd(cmd, false); - -out: - if (sd_is_zoned(sdkp) && ret == BLKPREP_OK) - return sd_zbc_write_lock_zone(cmd); + return sd_setup_write_same16_cmnd(cmd, false); - return ret; + return sd_setup_write_same10_cmnd(cmd, false); } static void sd_config_write_same(struct scsi_disk *sdkp) @@ -964,12 +955,6 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size); - if (sd_is_zoned(sdkp)) { - ret = sd_zbc_write_lock_zone(cmd); - if (ret != BLKPREP_OK) - return ret; - } - sector >>= ilog2(sdp->sector_size) - 9; nr_sectors >>= ilog2(sdp->sector_size) - 9; @@ -1004,9 +989,6 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) ret = scsi_init_io(cmd); rq->__data_len = nr_bytes; - if (sd_is_zoned(sdkp) && ret != BLKPREP_OK) - sd_zbc_write_unlock_zone(cmd); - return ret; } @@ -1036,19 +1018,12 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt) sector_t threshold; unsigned int this_count = blk_rq_sectors(rq); unsigned int dif, dix; - bool zoned_write = sd_is_zoned(sdkp) && rq_data_dir(rq) == WRITE; int ret; unsigned char protect; - if (zoned_write) { - ret = sd_zbc_write_lock_zone(SCpnt); - if (ret != BLKPREP_OK) - return ret; - } - ret = scsi_init_io(SCpnt); if (ret != BLKPREP_OK) - goto out; + return ret; WARN_ON_ONCE(SCpnt != rq->special); /* from here on until we're complete, any goto out @@ -1267,9 +1242,6 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt) */ ret = BLKPREP_OK; out: - if (zoned_write && ret != BLKPREP_OK) - sd_zbc_write_unlock_zone(SCpnt); - return ret; } @@ -1314,9 +1286,6 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt) struct request *rq = SCpnt->request; u8 *cmnd; - if (SCpnt->flags & SCMD_ZONE_WRITE_LOCK) - sd_zbc_write_unlock_zone(SCpnt); - if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) __free_page(rq->special_vec.bv_page); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 320de758323e..0d663b5e45bb 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -77,7 +77,6 @@ struct scsi_disk { unsigned int nr_zones; unsigned int zone_blocks; unsigned int zone_shift; - unsigned long *zones_wlock; unsigned int zones_optimal_open; unsigned int zones_optimal_nonseq; unsigned int zones_max_open; @@ -283,8 +282,6 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp) extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer); extern void sd_zbc_remove(struct scsi_disk *sdkp); extern void sd_zbc_print_zones(struct scsi_disk *sdkp); -extern int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd); -extern void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd); extern int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd); extern int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd); extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, @@ -302,14 +299,6 @@ static inline void sd_zbc_remove(struct scsi_disk *sdkp) {} static inline void sd_zbc_print_zones(struct scsi_disk *sdkp) {} -static inline int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd) -{ - /* Let the drive fail requests */ - return BLKPREP_OK; -} - -static inline void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd) {} - static inline int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd) { return BLKPREP_INVALID; diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index c715b8363ce0..6c348a211ebb 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -229,17 +229,6 @@ static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp) return logical_to_sectors(sdkp->device, sdkp->zone_blocks); } -/** - * sd_zbc_zone_no - Get the number of the zone conataining a sector. - * @sdkp: The target disk - * @sector: 512B sector address contained in the zone - */ -static inline unsigned int sd_zbc_zone_no(struct scsi_disk *sdkp, - sector_t sector) -{ - return sectors_to_logical(sdkp->device, sector) >> sdkp->zone_shift; -} - /** * sd_zbc_setup_reset_cmnd - Prepare a RESET WRITE POINTER scsi command. * @cmd: the command to setup @@ -278,78 +267,6 @@ int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) return BLKPREP_OK; } -/** - * sd_zbc_write_lock_zone - Write lock a sequential zone. - * @cmd: write command - * - * Called from sd_init_cmd() for write requests (standard write, write same or - * write zeroes operations). If the request target zone is not already locked, - * the zone is locked and BLKPREP_OK returned, allowing the request to proceed - * through dispatch in scsi_request_fn(). Otherwise, BLKPREP_DEFER is returned, - * forcing the request to wait for the zone to be unlocked, that is, for the - * previously issued write request targeting the same zone to complete. - * - * This is called from blk_peek_request() context with the queue lock held and - * before the request is removed from the scheduler. As a result, multiple - * contexts executing concurrently scsi_request_fn() cannot result in write - * sequence reordering as only a single write request per zone is allowed to - * proceed. - */ -int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd) -{ - struct request *rq = cmd->request; - struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); - sector_t sector = blk_rq_pos(rq); - sector_t zone_sectors = sd_zbc_zone_sectors(sdkp); - unsigned int zno = sd_zbc_zone_no(sdkp, sector); - - /* - * Note: Checks of the alignment of the write command on - * logical blocks is done in sd.c - */ - - /* Do not allow zone boundaries crossing on host-managed drives */ - if (blk_queue_zoned_model(sdkp->disk->queue) == BLK_ZONED_HM && - (sector & (zone_sectors - 1)) + blk_rq_sectors(rq) > zone_sectors) - return BLKPREP_KILL; - - /* - * Do not issue more than one write at a time per - * zone. This solves write ordering problems due to - * the unlocking of the request queue in the dispatch - * path in the non scsi-mq case. - */ - if (sdkp->zones_wlock && - test_and_set_bit(zno, sdkp->zones_wlock)) - return BLKPREP_DEFER; - - WARN_ON_ONCE(cmd->flags & SCMD_ZONE_WRITE_LOCK); - cmd->flags |= SCMD_ZONE_WRITE_LOCK; - - return BLKPREP_OK; -} - -/** - * sd_zbc_write_unlock_zone - Write unlock a sequential zone. - * @cmd: write command - * - * Called from sd_uninit_cmd(). Unlocking the request target zone will allow - * dispatching the next write request for the zone. - */ -void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd) -{ - struct request *rq = cmd->request; - struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); - - if (sdkp->zones_wlock && cmd->flags & SCMD_ZONE_WRITE_LOCK) { - unsigned int zno = sd_zbc_zone_no(sdkp, blk_rq_pos(rq)); - WARN_ON_ONCE(!test_bit(zno, sdkp->zones_wlock)); - cmd->flags &= ~SCMD_ZONE_WRITE_LOCK; - clear_bit_unlock(zno, sdkp->zones_wlock); - smp_mb__after_atomic(); - } -} - /** * sd_zbc_complete - ZBC command post processing. * @cmd: Completed command -- cgit From b67ecdec45b43a0c17a2e66e4d72303dfa3a8a96 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 5 Jan 2018 19:52:26 +0900 Subject: pinctrl: remove redundant mux_setting clear in pinmux_disable_setting() desc->mux_setting is set to NULL in pin_free() called just below. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/pinmux.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 55502fc4479c..82b18ef44ee4 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -493,8 +493,6 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) continue; } if (desc->mux_setting == &(setting->data.mux)) { - desc->mux_setting = NULL; - /* And release the pin */ pin_free(pctldev, pins[i], NULL); } else { const char *gname; -- cgit From ce8dc0943357a5d10b05dcf0556b537c1d7b8b1f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 6 Jan 2018 01:09:26 +0100 Subject: pinctrl: Add Microsemi Ocelot SoC driver The Microsemi Ocelot SoC has a few pins that can be used as GPIOs or take multiple other functions. Add a driver for the pinmuxing and the GPIOs. There is currently no support for interrupts. Signed-off-by: Alexandre Belloni Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 11 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-ocelot.c | 511 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 523 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-ocelot.c (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 1dd445116432..0f254b35c378 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -357,6 +357,17 @@ config PINCTRL_RK805 help This selects the pinctrl driver for RK805. +config PINCTRL_OCELOT + bool "Pinctrl driver for the Microsemi Ocelot SoCs" + default y + depends on OF + depends on MSCC_OCELOT || COMPILE_TEST + select GPIOLIB + select GENERIC_PINCONF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select REGMAP_MMIO + source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" source "drivers/pinctrl/berlin/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 2341228eb718..d3692633e9ed 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o +obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-y += bcm/ diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c new file mode 100644 index 000000000000..01a50d969111 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ocelot.c @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Microsemi SoCs pinctrl driver + * + * Author: + * License: Dual MIT/GPL + * Copyright (c) 2017 Microsemi Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "pinconf.h" +#include "pinmux.h" + +#define OCELOT_GPIO_OUT_SET 0x0 +#define OCELOT_GPIO_OUT_CLR 0x4 +#define OCELOT_GPIO_OUT 0x8 +#define OCELOT_GPIO_IN 0xc +#define OCELOT_GPIO_OE 0x10 +#define OCELOT_GPIO_INTR 0x14 +#define OCELOT_GPIO_INTR_ENA 0x18 +#define OCELOT_GPIO_INTR_IDENT 0x1c +#define OCELOT_GPIO_ALT0 0x20 +#define OCELOT_GPIO_ALT1 0x24 +#define OCELOT_GPIO_SD_MAP 0x28 + +#define OCELOT_PINS 22 +#define OCELOT_FUNC_PER_PIN 4 + +enum { + FUNC_NONE, + FUNC_GPIO, + FUNC_IRQ0_IN, + FUNC_IRQ0_OUT, + FUNC_IRQ1_IN, + FUNC_IRQ1_OUT, + FUNC_MIIM1, + FUNC_PCI_WAKE, + FUNC_PTP0, + FUNC_PTP1, + FUNC_PTP2, + FUNC_PTP3, + FUNC_PWM, + FUNC_RECO_CLK0, + FUNC_RECO_CLK1, + FUNC_SFP0, + FUNC_SFP1, + FUNC_SFP2, + FUNC_SFP3, + FUNC_SFP4, + FUNC_SFP5, + FUNC_SG0, + FUNC_SI, + FUNC_TACHO, + FUNC_TWI, + FUNC_TWI_SCL_M, + FUNC_UART, + FUNC_UART2, + FUNC_MAX +}; + +static const char *const ocelot_function_names[] = { + [FUNC_NONE] = "none", + [FUNC_GPIO] = "gpio", + [FUNC_IRQ0_IN] = "irq0_in", + [FUNC_IRQ0_OUT] = "irq0_out", + [FUNC_IRQ1_IN] = "irq1_in", + [FUNC_IRQ1_OUT] = "irq1_out", + [FUNC_MIIM1] = "miim1", + [FUNC_PCI_WAKE] = "pci_wake", + [FUNC_PTP0] = "ptp0", + [FUNC_PTP1] = "ptp1", + [FUNC_PTP2] = "ptp2", + [FUNC_PTP3] = "ptp3", + [FUNC_PWM] = "pwm", + [FUNC_RECO_CLK0] = "reco_clk0", + [FUNC_RECO_CLK1] = "reco_clk1", + [FUNC_SFP0] = "sfp0", + [FUNC_SFP1] = "sfp1", + [FUNC_SFP2] = "sfp2", + [FUNC_SFP3] = "sfp3", + [FUNC_SFP4] = "sfp4", + [FUNC_SFP5] = "sfp5", + [FUNC_SG0] = "sg0", + [FUNC_SI] = "si", + [FUNC_TACHO] = "tacho", + [FUNC_TWI] = "twi", + [FUNC_TWI_SCL_M] = "twi_scl_m", + [FUNC_UART] = "uart", + [FUNC_UART2] = "uart2", +}; + +struct ocelot_pmx_func { + const char **groups; + unsigned int ngroups; +}; + +struct ocelot_pin_caps { + unsigned int pin; + unsigned char functions[OCELOT_FUNC_PER_PIN]; +}; + +struct ocelot_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + struct gpio_chip gpio_chip; + struct regmap *map; + struct ocelot_pmx_func func[FUNC_MAX]; +}; + +#define OCELOT_P(p, f0, f1, f2) \ +static struct ocelot_pin_caps ocelot_pin_##p = { \ + .pin = p, \ + .functions = { \ + FUNC_GPIO, FUNC_##f0, FUNC_##f1, FUNC_##f2, \ + }, \ +} + +OCELOT_P(0, SG0, NONE, NONE); +OCELOT_P(1, SG0, NONE, NONE); +OCELOT_P(2, SG0, NONE, NONE); +OCELOT_P(3, SG0, NONE, NONE); +OCELOT_P(4, IRQ0_IN, IRQ0_OUT, TWI); +OCELOT_P(5, IRQ1_IN, IRQ1_OUT, PCI_WAKE); +OCELOT_P(6, UART, TWI_SCL_M, NONE); +OCELOT_P(7, UART, TWI_SCL_M, NONE); +OCELOT_P(8, SI, TWI_SCL_M, IRQ0_OUT); +OCELOT_P(9, SI, TWI_SCL_M, IRQ1_OUT); +OCELOT_P(10, PTP2, TWI_SCL_M, SFP0); +OCELOT_P(11, PTP3, TWI_SCL_M, SFP1); +OCELOT_P(12, UART2, TWI_SCL_M, SFP2); +OCELOT_P(13, UART2, TWI_SCL_M, SFP3); +OCELOT_P(14, MIIM1, TWI_SCL_M, SFP4); +OCELOT_P(15, MIIM1, TWI_SCL_M, SFP5); +OCELOT_P(16, TWI, NONE, SI); +OCELOT_P(17, TWI, TWI_SCL_M, SI); +OCELOT_P(18, PTP0, TWI_SCL_M, NONE); +OCELOT_P(19, PTP1, TWI_SCL_M, NONE); +OCELOT_P(20, RECO_CLK0, TACHO, NONE); +OCELOT_P(21, RECO_CLK1, PWM, NONE); + +#define OCELOT_PIN(n) { \ + .number = n, \ + .name = "GPIO_"#n, \ + .drv_data = &ocelot_pin_##n \ +} + +static const struct pinctrl_pin_desc ocelot_pins[] = { + OCELOT_PIN(0), + OCELOT_PIN(1), + OCELOT_PIN(2), + OCELOT_PIN(3), + OCELOT_PIN(4), + OCELOT_PIN(5), + OCELOT_PIN(6), + OCELOT_PIN(7), + OCELOT_PIN(8), + OCELOT_PIN(9), + OCELOT_PIN(10), + OCELOT_PIN(11), + OCELOT_PIN(12), + OCELOT_PIN(13), + OCELOT_PIN(14), + OCELOT_PIN(15), + OCELOT_PIN(16), + OCELOT_PIN(17), + OCELOT_PIN(18), + OCELOT_PIN(19), + OCELOT_PIN(20), + OCELOT_PIN(21), +}; + +static int ocelot_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(ocelot_function_names); +} + +static const char *ocelot_get_function_name(struct pinctrl_dev *pctldev, + unsigned int function) +{ + return ocelot_function_names[function]; +} + +static int ocelot_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char *const **groups, + unsigned *const num_groups) +{ + struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *groups = info->func[function].groups; + *num_groups = info->func[function].ngroups; + + return 0; +} + +static int ocelot_pin_function_idx(unsigned int pin, unsigned int function) +{ + struct ocelot_pin_caps *p = ocelot_pins[pin].drv_data; + int i; + + for (i = 0; i < OCELOT_FUNC_PER_PIN; i++) { + if (function == p->functions[i]) + return i; + } + + return -1; +} + +static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned int group) +{ + struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct ocelot_pin_caps *pin = ocelot_pins[group].drv_data; + int f; + + f = ocelot_pin_function_idx(group, selector); + if (f < 0) + return -EINVAL; + + /* + * f is encoded on two bits. + * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of + * ALT1 + * This is racy because both registers can't be updated at the same time + * but it doesn't matter much for now. + */ + regmap_update_bits(info->map, OCELOT_GPIO_ALT0, BIT(pin->pin), + f << pin->pin); + regmap_update_bits(info->map, OCELOT_GPIO_ALT1, BIT(pin->pin), + f << (pin->pin - 1)); + + return 0; +} + +static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin, bool input) +{ + struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + regmap_update_bits(info->map, OCELOT_GPIO_OE, BIT(pin), + input ? BIT(pin) : 0); + + return 0; +} + +static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + regmap_update_bits(info->map, OCELOT_GPIO_ALT0, BIT(offset), 0); + regmap_update_bits(info->map, OCELOT_GPIO_ALT1, BIT(offset), 0); + + return 0; +} + +static const struct pinmux_ops ocelot_pmx_ops = { + .get_functions_count = ocelot_get_functions_count, + .get_function_name = ocelot_get_function_name, + .get_function_groups = ocelot_get_function_groups, + .set_mux = ocelot_pinmux_set_mux, + .gpio_set_direction = ocelot_gpio_set_direction, + .gpio_request_enable = ocelot_gpio_request_enable, +}; + +static int ocelot_pctl_get_groups_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(ocelot_pins); +} + +static const char *ocelot_pctl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + return ocelot_pins[group].name; +} + +static int ocelot_pctl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + *pins = &ocelot_pins[group].number; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops ocelot_pctl_ops = { + .get_groups_count = ocelot_pctl_get_groups_count, + .get_group_name = ocelot_pctl_get_group_name, + .get_group_pins = ocelot_pctl_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static struct pinctrl_desc ocelot_desc = { + .name = "ocelot-pinctrl", + .pins = ocelot_pins, + .npins = ARRAY_SIZE(ocelot_pins), + .pctlops = &ocelot_pctl_ops, + .pmxops = &ocelot_pmx_ops, + .owner = THIS_MODULE, +}; + +static int ocelot_create_group_func_map(struct device *dev, + struct ocelot_pinctrl *info) +{ + u16 pins[ARRAY_SIZE(ocelot_pins)]; + int f, npins, i; + + for (f = 0; f < FUNC_MAX; f++) { + for (npins = 0, i = 0; i < ARRAY_SIZE(ocelot_pins); i++) { + if (ocelot_pin_function_idx(i, f) >= 0) + pins[npins++] = i; + } + + info->func[f].ngroups = npins; + info->func[f].groups = devm_kzalloc(dev, npins * + sizeof(char *), + GFP_KERNEL); + if (!info->func[f].groups) + return -ENOMEM; + + for (i = 0; i < npins; i++) + info->func[f].groups[i] = ocelot_pins[pins[i]].name; + } + + return 0; +} + +static int ocelot_pinctrl_register(struct platform_device *pdev, + struct ocelot_pinctrl *info) +{ + int ret; + + ret = ocelot_create_group_func_map(&pdev->dev, info); + if (ret) { + dev_err(&pdev->dev, "Unable to create group func map.\n"); + return ret; + } + + info->pctl = devm_pinctrl_register(&pdev->dev, &ocelot_desc, info); + if (IS_ERR(info->pctl)) { + dev_err(&pdev->dev, "Failed to register pinctrl\n"); + return PTR_ERR(info->pctl); + } + + return 0; +} + +static int ocelot_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + unsigned int val; + + regmap_read(info->map, OCELOT_GPIO_IN, &val); + + return !!(val & BIT(offset)); +} + +static void ocelot_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + + if (value) + regmap_write(info->map, OCELOT_GPIO_OUT_SET, BIT(offset)); + else + regmap_write(info->map, OCELOT_GPIO_OUT_CLR, BIT(offset)); +} + +static int ocelot_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + unsigned int val; + + regmap_read(info->map, OCELOT_GPIO_OE, &val); + + return !(val & BIT(offset)); +} + +static int ocelot_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int ocelot_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ocelot_pinctrl *info = gpiochip_get_data(chip); + unsigned int pin = BIT(offset); + + if (value) + regmap_write(info->map, OCELOT_GPIO_OUT_SET, pin); + else + regmap_write(info->map, OCELOT_GPIO_OUT_CLR, pin); + + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static const struct gpio_chip ocelot_gpiolib_chip = { + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .set = ocelot_gpio_set, + .get = ocelot_gpio_get, + .get_direction = ocelot_gpio_get_direction, + .direction_input = ocelot_gpio_direction_input, + .direction_output = ocelot_gpio_direction_output, + .owner = THIS_MODULE, +}; + +static int ocelot_gpiochip_register(struct platform_device *pdev, + struct ocelot_pinctrl *info) +{ + struct gpio_chip *gc; + int ret; + + info->gpio_chip = ocelot_gpiolib_chip; + + gc = &info->gpio_chip; + gc->ngpio = OCELOT_PINS; + gc->parent = &pdev->dev; + gc->base = 0; + gc->of_node = info->dev->of_node; + gc->label = "ocelot-gpio"; + + ret = devm_gpiochip_add_data(&pdev->dev, gc, info); + if (ret) + return ret; + + /* TODO: this can be used as an irqchip but no board is using that */ + + return 0; +} + +static const struct regmap_config ocelot_pinctrl_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x64, +}; + +static const struct of_device_id ocelot_pinctrl_of_match[] = { + { .compatible = "mscc,ocelot-pinctrl" }, + {}, +}; + +int ocelot_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ocelot_pinctrl *info; + void __iomem *base; + int ret; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + base = devm_ioremap_resource(dev, + platform_get_resource(pdev, IORESOURCE_MEM, 0)); + if (IS_ERR(base)) { + dev_err(dev, "Failed to ioremap registers\n"); + return PTR_ERR(base); + } + + info->map = devm_regmap_init_mmio(dev, base, + &ocelot_pinctrl_regmap_config); + if (IS_ERR(info->map)) { + dev_err(dev, "Failed to create regmap\n"); + return PTR_ERR(info->map); + } + dev_set_drvdata(dev, info->map); + info->dev = dev; + + ret = ocelot_pinctrl_register(pdev, info); + if (ret) + return ret; + + ret = ocelot_gpiochip_register(pdev, info); + if (ret) + return ret; + + return 0; +} + +static struct platform_driver ocelot_pinctrl_driver = { + .driver = { + .name = "pinctrl-ocelot", + .of_match_table = of_match_ptr(ocelot_pinctrl_of_match), + .suppress_bind_attrs = true, + }, + .probe = ocelot_pinctrl_probe, +}; +builtin_platform_driver(ocelot_pinctrl_driver); -- cgit From ba33f4f42e968854d8367fc4e55b07f835c55832 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Sat, 6 Jan 2018 15:25:53 +0100 Subject: pinctrl: imx6ul: add IOMUXC SNVS pinctrl driver for i.MX 6ULL On i.MX 6ULL, the BOOT_MODEx and TAMPERx pin MUX and CTRL registers are available in a separate IOMUXC_SNVS module. Add support for the IOMUXC_SNVS module to the i.MX 6UL pinctrl driver. Signed-off-by: Bai Ping Signed-off-by: Stefan Agner Reviewed-by: Rob Herring Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx6ul.c | 52 +++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/pinctrl-imx6ul.c b/drivers/pinctrl/freescale/pinctrl-imx6ul.c index 1aeb840aae1d..4580717ade19 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6ul.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6ul.c @@ -150,6 +150,21 @@ enum imx6ul_pads { MX6UL_PAD_CSI_DATA07 = 128, }; +enum imx6ull_lpsr_pads { + MX6ULL_PAD_BOOT_MODE0 = 0, + MX6ULL_PAD_BOOT_MODE1 = 1, + MX6ULL_PAD_SNVS_TAMPER0 = 2, + MX6ULL_PAD_SNVS_TAMPER1 = 3, + MX6ULL_PAD_SNVS_TAMPER2 = 4, + MX6ULL_PAD_SNVS_TAMPER3 = 5, + MX6ULL_PAD_SNVS_TAMPER4 = 6, + MX6ULL_PAD_SNVS_TAMPER5 = 7, + MX6ULL_PAD_SNVS_TAMPER6 = 8, + MX6ULL_PAD_SNVS_TAMPER7 = 9, + MX6ULL_PAD_SNVS_TAMPER8 = 10, + MX6ULL_PAD_SNVS_TAMPER9 = 11, +}; + /* Pad names for the pinmux subsystem */ static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0), @@ -283,20 +298,49 @@ static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA07), }; -static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = { +/* pad for i.MX6ULL lpsr pinmux */ +static const struct pinctrl_pin_desc imx6ull_snvs_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX6ULL_PAD_BOOT_MODE0), + IMX_PINCTRL_PIN(MX6ULL_PAD_BOOT_MODE1), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER0), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER1), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER2), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER3), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER4), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER5), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER6), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER7), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER8), + IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER9), +}; + +static const struct imx_pinctrl_soc_info imx6ul_pinctrl_info = { .pins = imx6ul_pinctrl_pads, .npins = ARRAY_SIZE(imx6ul_pinctrl_pads), .gpr_compatible = "fsl,imx6ul-iomuxc-gpr", }; -static struct of_device_id imx6ul_pinctrl_of_match[] = { - { .compatible = "fsl,imx6ul-iomuxc", }, +static const struct imx_pinctrl_soc_info imx6ull_snvs_pinctrl_info = { + .pins = imx6ull_snvs_pinctrl_pads, + .npins = ARRAY_SIZE(imx6ull_snvs_pinctrl_pads), + .flags = ZERO_OFFSET_VALID, +}; + +static const struct of_device_id imx6ul_pinctrl_of_match[] = { + { .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, }, + { .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, }, { /* sentinel */ } }; static int imx6ul_pinctrl_probe(struct platform_device *pdev) { - return imx_pinctrl_probe(pdev, &imx6ul_pinctrl_info); + const struct imx_pinctrl_soc_info *pinctrl_info; + + pinctrl_info = of_device_get_match_data(&pdev->dev); + if (!pinctrl_info) + return -ENODEV; + + return imx_pinctrl_probe(pdev, pinctrl_info); } static struct platform_driver imx6ul_pinctrl_driver = { -- cgit From 7c3012c8553b9f6688a02387dbc05850ac643c88 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 6 Jan 2018 20:40:04 +0100 Subject: pinctrl: mcp23s08: Combine two function calls into one in mcp23s08_dbg_show() * Print a line break together with other data in a single function call. * Adjust indentation. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-mcp23s08.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index e6ad36dea3e5..95d548f3ba53 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -748,13 +748,12 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) if (!label) continue; - seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s", - chip->base + t, bank, t, label, - (iodir & mask) ? "in " : "out", - (gpio & mask) ? "hi" : "lo", - (gppu & mask) ? "up" : " "); + seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s\n", + chip->base + t, bank, t, label, + (iodir & mask) ? "in " : "out", + (gpio & mask) ? "hi" : "lo", + (gppu & mask) ? "up" : " "); /* NOTE: ignoring the irq-related registers */ - seq_puts(s, "\n"); } done: mutex_unlock(&mcp->lock); -- cgit From a3a093ae02e2ae81499ad9e78516dccd72906c25 Mon Sep 17 00:00:00 2001 From: "Khan, Imran" Date: Sun, 7 Jan 2018 18:15:30 -0800 Subject: pinctrl: qcom: Add msm8998 pinctrl driver Add initial pinctrl driver to support pin configuration with pinctrl framework for msm8998. Signed-off-by: Imran Khan Acked-by: Rob Herring [bjorn: Consolidated function groups] Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/Kconfig | 8 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-msm8998.c | 1590 ++++++++++++++++++++++++++++++++ 3 files changed, 1599 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-msm8998.c (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 9e504dbc7fb5..fcaaa92d76df 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -106,6 +106,14 @@ config PINCTRL_MSM8996 This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found in the Qualcomm MSM8996 platform. +config PINCTRL_MSM8998 + tristate "Qualcomm MSM8998 pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm TLMM block found in the Qualcomm MSM8998 platform. + config PINCTRL_QDF2XXX tristate "Qualcomm Technologies QDF2xxx pin controller driver" depends on GPIOLIB && ACPI diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index a1db345ded1c..8cb45bbd2e7f 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o obj-$(CONFIG_PINCTRL_MSM8994) += pinctrl-msm8994.o obj-$(CONFIG_PINCTRL_MSM8996) += pinctrl-msm8996.o +obj-$(CONFIG_PINCTRL_MSM8998) += pinctrl-msm8998.o obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o obj-$(CONFIG_PINCTRL_MDM9615) += pinctrl-mdm9615.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c new file mode 100644 index 000000000000..c33953183013 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c @@ -0,0 +1,1590 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +#define NORTH 0x500000 +#define WEST 0x100000 +#define EAST 0x900000 + +#define FUNCTION(fname) \ + [msm_mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = 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 \ + }, \ + .nfuncs = 10, \ + .ctl_reg = base + 0x1000 * id, \ + .io_reg = base + 0x4 + 0x1000 * id, \ + .intr_cfg_reg = base + 0x8 + 0x1000 * id, \ + .intr_status_reg = base + 0xc + 0x1000 * id, \ + .intr_target_reg = base + 0x8 + 0x1000 * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .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) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = 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, offset) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .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 msm8998_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, "SDC2_CLK"), + PINCTRL_PIN(151, "SDC2_CMD"), + PINCTRL_PIN(152, "SDC2_DATA"), + PINCTRL_PIN(153, "UFS_RESET"), +}; + +#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); + +static const unsigned int sdc2_clk_pins[] = { 150 }; +static const unsigned int sdc2_cmd_pins[] = { 151 }; +static const unsigned int sdc2_data_pins[] = { 152 }; +static const unsigned int ufs_reset_pins[] = { 153 }; + +enum msm8998_functions { + msm_mux_adsp_ext, + msm_mux_agera_pll, + msm_mux_atest_char, + msm_mux_atest_gpsadc0, + msm_mux_atest_gpsadc1, + msm_mux_atest_tsens, + msm_mux_atest_tsens2, + msm_mux_atest_usb1, + msm_mux_atest_usb10, + msm_mux_atest_usb11, + msm_mux_atest_usb12, + msm_mux_atest_usb13, + msm_mux_audio_ref, + msm_mux_bimc_dte0, + msm_mux_bimc_dte1, + msm_mux_blsp10_spi, + msm_mux_blsp10_spi_a, + msm_mux_blsp10_spi_b, + msm_mux_blsp11_i2c, + msm_mux_blsp1_spi, + msm_mux_blsp1_spi_a, + msm_mux_blsp1_spi_b, + msm_mux_blsp2_spi, + msm_mux_blsp9_spi, + msm_mux_blsp_i2c1, + msm_mux_blsp_i2c10, + msm_mux_blsp_i2c11, + msm_mux_blsp_i2c12, + msm_mux_blsp_i2c2, + msm_mux_blsp_i2c3, + msm_mux_blsp_i2c4, + msm_mux_blsp_i2c5, + msm_mux_blsp_i2c6, + msm_mux_blsp_i2c7, + msm_mux_blsp_i2c8, + msm_mux_blsp_i2c9, + msm_mux_blsp_spi1, + msm_mux_blsp_spi10, + msm_mux_blsp_spi11, + msm_mux_blsp_spi12, + msm_mux_blsp_spi2, + msm_mux_blsp_spi3, + msm_mux_blsp_spi4, + msm_mux_blsp_spi5, + msm_mux_blsp_spi6, + msm_mux_blsp_spi7, + msm_mux_blsp_spi8, + msm_mux_blsp_spi9, + msm_mux_blsp_uart1_a, + msm_mux_blsp_uart1_b, + msm_mux_blsp_uart2_a, + msm_mux_blsp_uart2_b, + msm_mux_blsp_uart3_a, + msm_mux_blsp_uart3_b, + msm_mux_blsp_uart7_a, + msm_mux_blsp_uart7_b, + msm_mux_blsp_uart8, + msm_mux_blsp_uart8_a, + msm_mux_blsp_uart8_b, + msm_mux_blsp_uart9_a, + msm_mux_blsp_uart9_b, + msm_mux_blsp_uim1_a, + msm_mux_blsp_uim1_b, + msm_mux_blsp_uim2_a, + msm_mux_blsp_uim2_b, + msm_mux_blsp_uim3_a, + msm_mux_blsp_uim3_b, + msm_mux_blsp_uim7_a, + msm_mux_blsp_uim7_b, + msm_mux_blsp_uim8_a, + msm_mux_blsp_uim8_b, + msm_mux_blsp_uim9_a, + msm_mux_blsp_uim9_b, + msm_mux_bt_reset, + msm_mux_btfm_slimbus, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c, + msm_mux_cci_timer0, + msm_mux_cci_timer1, + msm_mux_cci_timer2, + msm_mux_cci_timer3, + msm_mux_cci_timer4, + msm_mux_cri_trng, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_dbg_out, + msm_mux_ddr_bist, + msm_mux_edp_hot, + msm_mux_edp_lcd, + msm_mux_gcc_gp1_a, + msm_mux_gcc_gp1_b, + msm_mux_gcc_gp2_a, + msm_mux_gcc_gp2_b, + msm_mux_gcc_gp3_a, + msm_mux_gcc_gp3_b, + msm_mux_gpio, + msm_mux_hdmi_cec, + msm_mux_hdmi_ddc, + msm_mux_hdmi_hot, + msm_mux_hdmi_rcv, + msm_mux_isense_dbg, + msm_mux_jitter_bist, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_lpass_slimbus, + msm_mux_m_voc, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_mdp_vsync_a, + msm_mux_mdp_vsync_b, + msm_mux_modem_tsync, + msm_mux_mss_lte, + msm_mux_nav_dr, + msm_mux_nav_pps, + msm_mux_pa_indicator, + msm_mux_pci_e0, + msm_mux_phase_flag, + msm_mux_pll_bypassnl, + msm_mux_pll_reset, + msm_mux_pri_mi2s, + msm_mux_pri_mi2s_ws, + msm_mux_prng_rosc, + msm_mux_pwr_crypto, + msm_mux_pwr_modem, + msm_mux_pwr_nav, + msm_mux_qdss_cti0_a, + msm_mux_qdss_cti0_b, + msm_mux_qdss_cti1_a, + msm_mux_qdss_cti1_b, + msm_mux_qdss, + msm_mux_qlink_enable, + msm_mux_qlink_request, + msm_mux_qua_mi2s, + msm_mux_sd_card, + msm_mux_sd_write, + msm_mux_sdc40, + msm_mux_sdc41, + msm_mux_sdc42, + msm_mux_sdc43, + msm_mux_sdc4_clk, + msm_mux_sdc4_cmd, + msm_mux_sec_mi2s, + msm_mux_sp_cmu, + msm_mux_spkr_i2s, + msm_mux_ssbi1, + msm_mux_ssc_irq, + msm_mux_ter_mi2s, + msm_mux_tgu_ch0, + msm_mux_tgu_ch1, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_tsif1_clk, + msm_mux_tsif1_data, + msm_mux_tsif1_en, + msm_mux_tsif1_error, + msm_mux_tsif1_sync, + msm_mux_tsif2_clk, + msm_mux_tsif2_data, + msm_mux_tsif2_en, + msm_mux_tsif2_error, + msm_mux_tsif2_sync, + msm_mux_uim1_clk, + msm_mux_uim1_data, + msm_mux_uim1_present, + msm_mux_uim1_reset, + msm_mux_uim2_clk, + msm_mux_uim2_data, + msm_mux_uim2_present, + msm_mux_uim2_reset, + msm_mux_uim_batt, + msm_mux_usb_phy, + msm_mux_vfr_1, + msm_mux_vsense_clkout, + msm_mux_vsense_data0, + msm_mux_vsense_data1, + msm_mux_vsense_mode, + msm_mux_wlan1_adc0, + msm_mux_wlan1_adc1, + msm_mux_wlan2_adc0, + msm_mux_wlan2_adc1, + 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", +}; +static const char * const blsp_spi1_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; +static const char * const blsp_uim1_a_groups[] = { + "gpio0", "gpio1", +}; +static const char * const blsp_uart1_a_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; +static const char * const blsp_i2c1_groups[] = { + "gpio2", "gpio3", +}; +static const char * const blsp_spi8_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; +static const char * const blsp_uart8_a_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; +static const char * const blsp_uim8_a_groups[] = { + "gpio4", "gpio5", +}; +static const char * const qdss_cti0_b_groups[] = { + "gpio4", "gpio5", +}; +static const char * const blsp_i2c8_groups[] = { + "gpio6", "gpio7", +}; +static const char * const ddr_bist_groups[] = { + "gpio7", "gpio8", "gpio9", "gpio10", +}; +static const char * const atest_tsens2_groups[] = { + "gpio7", +}; +static const char * const atest_usb1_groups[] = { + "gpio7", +}; +static const char * const blsp_spi4_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11", +}; +static const char * const blsp_uart1_b_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11", +}; +static const char * const blsp_uim1_b_groups[] = { + "gpio8", "gpio9", +}; +static const char * const wlan1_adc1_groups[] = { + "gpio8", +}; +static const char * const atest_usb13_groups[] = { + "gpio8", +}; +static const char * const bimc_dte1_groups[] = { + "gpio8", "gpio10", +}; +static const char * const tsif1_sync_groups[] = { + "gpio9", +}; +static const char * const wlan1_adc0_groups[] = { + "gpio9", +}; +static const char * const atest_usb12_groups[] = { + "gpio9", +}; +static const char * const bimc_dte0_groups[] = { + "gpio9", "gpio11", +}; +static const char * const mdp_vsync_a_groups[] = { + "gpio10", "gpio11", +}; +static const char * const blsp_i2c4_groups[] = { + "gpio10", "gpio11", +}; +static const char * const atest_gpsadc1_groups[] = { + "gpio10", +}; +static const char * const wlan2_adc1_groups[] = { + "gpio10", +}; +static const char * const atest_usb11_groups[] = { + "gpio10", +}; +static const char * const edp_lcd_groups[] = { + "gpio11", +}; +static const char * const dbg_out_groups[] = { + "gpio11", +}; +static const char * const atest_gpsadc0_groups[] = { + "gpio11", +}; +static const char * const wlan2_adc0_groups[] = { + "gpio11", +}; +static const char * const atest_usb10_groups[] = { + "gpio11", +}; +static const char * const mdp_vsync_groups[] = { + "gpio12", +}; +static const char * const m_voc_groups[] = { + "gpio12", +}; +static const char * const cam_mclk_groups[] = { + "gpio13", "gpio14", "gpio15", "gpio16", +}; +static const char * const pll_bypassnl_groups[] = { + "gpio13", +}; +static const char * const qdss_groups[] = { + "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", + "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", + "gpio27", "gpio28", "gpio29", "gpio30", "gpio41", "gpio42", "gpio43", + "gpio44", "gpio75", "gpio76", "gpio77", "gpio79", "gpio80", "gpio93", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", + "gpio123", "gpio124", +}; +static const char * const pll_reset_groups[] = { + "gpio14", +}; +static const char * const cci_i2c_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", +}; +static const char * const phase_flag_groups[] = { + "gpio18", "gpio19", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio89", "gpio91", "gpio92", "gpio96", "gpio114", "gpio115", + "gpio116", "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", + "gpio122", "gpio123", "gpio124", "gpio125", "gpio126", "gpio128", + "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134", +}; +static const char * const cci_timer4_groups[] = { + "gpio25", +}; +static const char * const blsp2_spi_groups[] = { + "gpio25", "gpio29", "gpio30", +}; +static const char * const cci_timer0_groups[] = { + "gpio21", +}; +static const char * const vsense_data0_groups[] = { + "gpio21", +}; +static const char * const cci_timer1_groups[] = { + "gpio22", +}; +static const char * const vsense_data1_groups[] = { + "gpio22", +}; +static const char * const cci_timer2_groups[] = { + "gpio23", +}; +static const char * const blsp1_spi_b_groups[] = { + "gpio23", "gpio28", +}; +static const char * const vsense_mode_groups[] = { + "gpio23", +}; +static const char * const cci_timer3_groups[] = { + "gpio24", +}; +static const char * const cci_async_groups[] = { + "gpio24", "gpio25", "gpio26", +}; +static const char * const blsp1_spi_a_groups[] = { + "gpio24", "gpio27", +}; +static const char * const vsense_clkout_groups[] = { + "gpio24", +}; +static const char * const hdmi_rcv_groups[] = { + "gpio30", +}; +static const char * const hdmi_cec_groups[] = { + "gpio31", +}; +static const char * const blsp_spi2_groups[] = { + "gpio31", "gpio32", "gpio33", "gpio34", +}; +static const char * const blsp_uart2_a_groups[] = { + "gpio31", "gpio32", "gpio33", "gpio34", +}; +static const char * const blsp_uim2_a_groups[] = { + "gpio31", "gpio34", +}; +static const char * const pwr_modem_groups[] = { + "gpio31", +}; +static const char * const hdmi_ddc_groups[] = { + "gpio32", "gpio33", +}; +static const char * const blsp_i2c2_groups[] = { + "gpio32", "gpio33", +}; +static const char * const pwr_nav_groups[] = { + "gpio32", +}; +static const char * const pwr_crypto_groups[] = { + "gpio33", +}; +static const char * const hdmi_hot_groups[] = { + "gpio34", +}; +static const char * const edp_hot_groups[] = { + "gpio34", +}; +static const char * const pci_e0_groups[] = { + "gpio35", "gpio36", "gpio37", +}; +static const char * const jitter_bist_groups[] = { + "gpio35", +}; +static const char * const agera_pll_groups[] = { + "gpio36", "gpio37", +}; +static const char * const atest_tsens_groups[] = { + "gpio36", +}; +static const char * const usb_phy_groups[] = { + "gpio38", +}; +static const char * const lpass_slimbus_groups[] = { + "gpio39", "gpio70", "gpio71", "gpio72", +}; +static const char * const sd_write_groups[] = { + "gpio40", +}; +static const char * const tsif1_error_groups[] = { + "gpio40", +}; +static const char * const blsp_spi6_groups[] = { + "gpio41", "gpio42", "gpio43", "gpio44", +}; +static const char * const blsp_uart3_b_groups[] = { + "gpio41", "gpio42", "gpio43", "gpio44", +}; +static const char * const blsp_uim3_b_groups[] = { + "gpio41", "gpio42", +}; +static const char * const blsp_i2c6_groups[] = { + "gpio43", "gpio44", +}; +static const char * const bt_reset_groups[] = { + "gpio45", +}; +static const char * const blsp_spi3_groups[] = { + "gpio45", "gpio46", "gpio47", "gpio48", +}; +static const char * const blsp_uart3_a_groups[] = { + "gpio45", "gpio46", "gpio47", "gpio48", +}; +static const char * const blsp_uim3_a_groups[] = { + "gpio45", "gpio46", +}; +static const char * const blsp_i2c3_groups[] = { + "gpio47", "gpio48", +}; +static const char * const blsp_spi9_groups[] = { + "gpio49", "gpio50", "gpio51", "gpio52", +}; +static const char * const blsp_uart9_a_groups[] = { + "gpio49", "gpio50", "gpio51", "gpio52", +}; +static const char * const blsp_uim9_a_groups[] = { + "gpio49", "gpio50", +}; +static const char * const blsp10_spi_b_groups[] = { + "gpio49", "gpio50", +}; +static const char * const qdss_cti0_a_groups[] = { + "gpio49", "gpio50", +}; +static const char * const blsp_i2c9_groups[] = { + "gpio51", "gpio52", +}; +static const char * const blsp10_spi_a_groups[] = { + "gpio51", "gpio52", +}; +static const char * const blsp_spi7_groups[] = { + "gpio53", "gpio54", "gpio55", "gpio56", +}; +static const char * const blsp_uart7_a_groups[] = { + "gpio53", "gpio54", "gpio55", "gpio56", +}; +static const char * const blsp_uim7_a_groups[] = { + "gpio53", "gpio54", +}; +static const char * const blsp_i2c7_groups[] = { + "gpio55", "gpio56", +}; +static const char * const qua_mi2s_groups[] = { + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", +}; +static const char * const blsp10_spi_groups[] = { + "gpio57", +}; +static const char * const gcc_gp1_a_groups[] = { + "gpio57", +}; +static const char * const ssc_irq_groups[] = { + "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio78", + "gpio79", "gpio80", "gpio117", "gpio118", "gpio119", "gpio120", + "gpio121", "gpio122", "gpio123", "gpio124", "gpio125", +}; +static const char * const blsp_spi11_groups[] = { + "gpio58", "gpio59", "gpio60", "gpio61", +}; +static const char * const blsp_uart8_b_groups[] = { + "gpio58", "gpio59", "gpio60", "gpio61", +}; +static const char * const blsp_uim8_b_groups[] = { + "gpio58", "gpio59", +}; +static const char * const gcc_gp2_a_groups[] = { + "gpio58", +}; +static const char * const qdss_cti1_a_groups[] = { + "gpio58", "gpio59", +}; +static const char * const gcc_gp3_a_groups[] = { + "gpio59", +}; +static const char * const blsp_i2c11_groups[] = { + "gpio60", "gpio61", +}; +static const char * const cri_trng0_groups[] = { + "gpio60", +}; +static const char * const cri_trng1_groups[] = { + "gpio61", +}; +static const char * const cri_trng_groups[] = { + "gpio62", +}; +static const char * const pri_mi2s_groups[] = { + "gpio64", "gpio65", "gpio67", "gpio68", +}; +static const char * const sp_cmu_groups[] = { + "gpio64", +}; +static const char * const blsp_spi10_groups[] = { + "gpio65", "gpio66", "gpio67", "gpio68", +}; +static const char * const blsp_uart7_b_groups[] = { + "gpio65", "gpio66", "gpio67", "gpio68", +}; +static const char * const blsp_uim7_b_groups[] = { + "gpio65", "gpio66", +}; +static const char * const pri_mi2s_ws_groups[] = { + "gpio66", +}; +static const char * const blsp_i2c10_groups[] = { + "gpio67", "gpio68", +}; +static const char * const spkr_i2s_groups[] = { + "gpio69", "gpio70", "gpio71", "gpio72", +}; +static const char * const audio_ref_groups[] = { + "gpio69", +}; +static const char * const blsp9_spi_groups[] = { + "gpio70", "gpio71", "gpio72", +}; +static const char * const tsense_pwm1_groups[] = { + "gpio71", +}; +static const char * const tsense_pwm2_groups[] = { + "gpio71", +}; +static const char * const btfm_slimbus_groups[] = { + "gpio73", "gpio74", +}; +static const char * const ter_mi2s_groups[] = { + "gpio74", "gpio75", "gpio76", "gpio77", "gpio78", +}; +static const char * const gcc_gp1_b_groups[] = { + "gpio78", +}; +static const char * const sec_mi2s_groups[] = { + "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", +}; +static const char * const blsp_spi12_groups[] = { + "gpio81", "gpio82", "gpio83", "gpio84", +}; +static const char * const blsp_uart9_b_groups[] = { + "gpio81", "gpio82", "gpio83", "gpio84", +}; +static const char * const blsp_uim9_b_groups[] = { + "gpio81", "gpio82", +}; +static const char * const gcc_gp2_b_groups[] = { + "gpio81", +}; +static const char * const gcc_gp3_b_groups[] = { + "gpio82", +}; +static const char * const blsp_i2c12_groups[] = { + "gpio83", "gpio84", +}; +static const char * const blsp_spi5_groups[] = { + "gpio85", "gpio86", "gpio87", "gpio88", +}; +static const char * const blsp_uart2_b_groups[] = { + "gpio85", "gpio86", "gpio87", "gpio88", +}; +static const char * const blsp_uim2_b_groups[] = { + "gpio85", "gpio86", +}; +static const char * const blsp_i2c5_groups[] = { + "gpio87", "gpio88", +}; +static const char * const tsif1_clk_groups[] = { + "gpio89", +}; +static const char * const tsif1_en_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync0_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync1_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync2_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync3_groups[] = { + "gpio90", +}; +static const char * const blsp1_spi_groups[] = { + "gpio90", +}; +static const char * const tgu_ch0_groups[] = { + "gpio90", +}; +static const char * const qdss_cti1_b_groups[] = { + "gpio90", "gpio91", +}; +static const char * const tsif1_data_groups[] = { + "gpio91", +}; +static const char * const sdc4_cmd_groups[] = { + "gpio91", +}; +static const char * const tgu_ch1_groups[] = { + "gpio91", +}; +static const char * const tsif2_error_groups[] = { + "gpio92", +}; +static const char * const sdc43_groups[] = { + "gpio92", +}; +static const char * const vfr_1_groups[] = { + "gpio92", +}; +static const char * const tsif2_clk_groups[] = { + "gpio93", +}; +static const char * const sdc4_clk_groups[] = { + "gpio93", +}; +static const char * const tsif2_en_groups[] = { + "gpio94", +}; +static const char * const sdc42_groups[] = { + "gpio94", +}; +static const char * const sd_card_groups[] = { + "gpio95", +}; +static const char * const tsif2_data_groups[] = { + "gpio95", +}; +static const char * const sdc41_groups[] = { + "gpio95", +}; +static const char * const tsif2_sync_groups[] = { + "gpio96", +}; +static const char * const sdc40_groups[] = { + "gpio96", +}; +static const char * const mdp_vsync_b_groups[] = { + "gpio97", "gpio98", +}; +static const char * const ldo_en_groups[] = { + "gpio97", +}; +static const char * const ldo_update_groups[] = { + "gpio98", +}; +static const char * const blsp_uart8_groups[] = { + "gpio100", "gpio101", +}; +static const char * const blsp11_i2c_groups[] = { + "gpio102", "gpio103", +}; +static const char * const prng_rosc_groups[] = { + "gpio102", +}; +static const char * const uim2_data_groups[] = { + "gpio105", +}; +static const char * const uim2_clk_groups[] = { + "gpio106", +}; +static const char * const uim2_reset_groups[] = { + "gpio107", +}; +static const char * const uim2_present_groups[] = { + "gpio108", +}; +static const char * const uim1_data_groups[] = { + "gpio109", +}; +static const char * const uim1_clk_groups[] = { + "gpio110", +}; +static const char * const uim1_reset_groups[] = { + "gpio111", +}; +static const char * const uim1_present_groups[] = { + "gpio112", +}; +static const char * const uim_batt_groups[] = { + "gpio113", +}; +static const char * const nav_dr_groups[] = { + "gpio115", +}; +static const char * const atest_char_groups[] = { + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", +}; +static const char * const adsp_ext_groups[] = { + "gpio118", +}; +static const char * const modem_tsync_groups[] = { + "gpio128", +}; +static const char * const nav_pps_groups[] = { + "gpio128", +}; +static const char * const qlink_request_groups[] = { + "gpio130", +}; +static const char * const qlink_enable_groups[] = { + "gpio131", +}; +static const char * const pa_indicator_groups[] = { + "gpio135", +}; +static const char * const ssbi1_groups[] = { + "gpio142", +}; +static const char * const isense_dbg_groups[] = { + "gpio143", +}; +static const char * const mss_lte_groups[] = { + "gpio144", "gpio145", +}; + +static const struct msm_function msm8998_functions[] = { + FUNCTION(gpio), + FUNCTION(adsp_ext), + FUNCTION(agera_pll), + FUNCTION(atest_char), + FUNCTION(atest_gpsadc0), + FUNCTION(atest_gpsadc1), + FUNCTION(atest_tsens), + FUNCTION(atest_tsens2), + FUNCTION(atest_usb1), + FUNCTION(atest_usb10), + FUNCTION(atest_usb11), + FUNCTION(atest_usb12), + FUNCTION(atest_usb13), + FUNCTION(audio_ref), + FUNCTION(bimc_dte0), + FUNCTION(bimc_dte1), + FUNCTION(blsp10_spi), + FUNCTION(blsp10_spi_a), + FUNCTION(blsp10_spi_b), + FUNCTION(blsp11_i2c), + FUNCTION(blsp1_spi), + FUNCTION(blsp1_spi_a), + FUNCTION(blsp1_spi_b), + FUNCTION(blsp2_spi), + FUNCTION(blsp9_spi), + FUNCTION(blsp_i2c1), + FUNCTION(blsp_i2c2), + FUNCTION(blsp_i2c3), + FUNCTION(blsp_i2c4), + FUNCTION(blsp_i2c5), + FUNCTION(blsp_i2c6), + FUNCTION(blsp_i2c7), + FUNCTION(blsp_i2c8), + FUNCTION(blsp_i2c9), + FUNCTION(blsp_i2c10), + FUNCTION(blsp_i2c11), + FUNCTION(blsp_i2c12), + FUNCTION(blsp_spi1), + FUNCTION(blsp_spi2), + FUNCTION(blsp_spi3), + FUNCTION(blsp_spi4), + FUNCTION(blsp_spi5), + FUNCTION(blsp_spi6), + FUNCTION(blsp_spi7), + FUNCTION(blsp_spi8), + FUNCTION(blsp_spi9), + FUNCTION(blsp_spi10), + FUNCTION(blsp_spi11), + FUNCTION(blsp_spi12), + FUNCTION(blsp_uart1_a), + FUNCTION(blsp_uart1_b), + FUNCTION(blsp_uart2_a), + FUNCTION(blsp_uart2_b), + FUNCTION(blsp_uart3_a), + FUNCTION(blsp_uart3_b), + FUNCTION(blsp_uart7_a), + FUNCTION(blsp_uart7_b), + FUNCTION(blsp_uart8), + FUNCTION(blsp_uart8_a), + FUNCTION(blsp_uart8_b), + FUNCTION(blsp_uart9_a), + FUNCTION(blsp_uart9_b), + FUNCTION(blsp_uim1_a), + FUNCTION(blsp_uim1_b), + FUNCTION(blsp_uim2_a), + FUNCTION(blsp_uim2_b), + FUNCTION(blsp_uim3_a), + FUNCTION(blsp_uim3_b), + FUNCTION(blsp_uim7_a), + FUNCTION(blsp_uim7_b), + FUNCTION(blsp_uim8_a), + FUNCTION(blsp_uim8_b), + FUNCTION(blsp_uim9_a), + FUNCTION(blsp_uim9_b), + FUNCTION(bt_reset), + FUNCTION(btfm_slimbus), + FUNCTION(cam_mclk), + FUNCTION(cci_async), + FUNCTION(cci_i2c), + FUNCTION(cci_timer0), + FUNCTION(cci_timer1), + FUNCTION(cci_timer2), + FUNCTION(cci_timer3), + FUNCTION(cci_timer4), + FUNCTION(cri_trng), + FUNCTION(cri_trng0), + FUNCTION(cri_trng1), + FUNCTION(dbg_out), + FUNCTION(ddr_bist), + FUNCTION(edp_hot), + FUNCTION(edp_lcd), + FUNCTION(gcc_gp1_a), + FUNCTION(gcc_gp1_b), + FUNCTION(gcc_gp2_a), + FUNCTION(gcc_gp2_b), + FUNCTION(gcc_gp3_a), + FUNCTION(gcc_gp3_b), + FUNCTION(hdmi_cec), + FUNCTION(hdmi_ddc), + FUNCTION(hdmi_hot), + FUNCTION(hdmi_rcv), + FUNCTION(isense_dbg), + FUNCTION(jitter_bist), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(lpass_slimbus), + FUNCTION(m_voc), + FUNCTION(mdp_vsync), + FUNCTION(mdp_vsync0), + FUNCTION(mdp_vsync1), + FUNCTION(mdp_vsync2), + FUNCTION(mdp_vsync3), + FUNCTION(mdp_vsync_a), + FUNCTION(mdp_vsync_b), + FUNCTION(modem_tsync), + FUNCTION(mss_lte), + FUNCTION(nav_dr), + FUNCTION(nav_pps), + FUNCTION(pa_indicator), + FUNCTION(pci_e0), + FUNCTION(phase_flag), + FUNCTION(pll_bypassnl), + FUNCTION(pll_reset), + FUNCTION(pri_mi2s), + FUNCTION(pri_mi2s_ws), + FUNCTION(prng_rosc), + FUNCTION(pwr_crypto), + FUNCTION(pwr_modem), + FUNCTION(pwr_nav), + FUNCTION(qdss_cti0_a), + FUNCTION(qdss_cti0_b), + FUNCTION(qdss_cti1_a), + FUNCTION(qdss_cti1_b), + FUNCTION(qdss), + FUNCTION(qlink_enable), + FUNCTION(qlink_request), + FUNCTION(qua_mi2s), + FUNCTION(sd_card), + FUNCTION(sd_write), + FUNCTION(sdc40), + FUNCTION(sdc41), + FUNCTION(sdc42), + FUNCTION(sdc43), + FUNCTION(sdc4_clk), + FUNCTION(sdc4_cmd), + FUNCTION(sec_mi2s), + FUNCTION(sp_cmu), + FUNCTION(spkr_i2s), + FUNCTION(ssbi1), + FUNCTION(ssc_irq), + FUNCTION(ter_mi2s), + FUNCTION(tgu_ch0), + FUNCTION(tgu_ch1), + FUNCTION(tsense_pwm1), + FUNCTION(tsense_pwm2), + FUNCTION(tsif1_clk), + FUNCTION(tsif1_data), + FUNCTION(tsif1_en), + FUNCTION(tsif1_error), + FUNCTION(tsif1_sync), + FUNCTION(tsif2_clk), + FUNCTION(tsif2_data), + FUNCTION(tsif2_en), + FUNCTION(tsif2_error), + FUNCTION(tsif2_sync), + FUNCTION(uim1_clk), + FUNCTION(uim1_data), + FUNCTION(uim1_present), + FUNCTION(uim1_reset), + FUNCTION(uim2_clk), + FUNCTION(uim2_data), + FUNCTION(uim2_present), + FUNCTION(uim2_reset), + FUNCTION(uim_batt), + FUNCTION(usb_phy), + FUNCTION(vfr_1), + FUNCTION(vsense_clkout), + FUNCTION(vsense_data0), + FUNCTION(vsense_data1), + FUNCTION(vsense_mode), + FUNCTION(wlan1_adc0), + FUNCTION(wlan1_adc1), + FUNCTION(wlan2_adc0), + FUNCTION(wlan2_adc1), +}; + +static const struct msm_pingroup msm8998_groups[] = { + PINGROUP(0, EAST, blsp_spi1, blsp_uart1_a, blsp_uim1_a, _, _, _, _, _, _), + PINGROUP(1, EAST, blsp_spi1, blsp_uart1_a, blsp_uim1_a, _, _, _, _, _, _), + PINGROUP(2, EAST, blsp_spi1, blsp_uart1_a, blsp_i2c1, _, _, _, _, _, _), + PINGROUP(3, EAST, blsp_spi1, blsp_uart1_a, blsp_i2c1, _, _, _, _, _, _), + PINGROUP(4, WEST, blsp_spi8, blsp_uart8_a, blsp_uim8_a, _, qdss_cti0_b, _, _, _, _), + PINGROUP(5, WEST, blsp_spi8, blsp_uart8_a, blsp_uim8_a, _, qdss_cti0_b, _, _, _, _), + PINGROUP(6, WEST, blsp_spi8, blsp_uart8_a, blsp_i2c8, _, _, _, _, _, _), + PINGROUP(7, WEST, blsp_spi8, blsp_uart8_a, blsp_i2c8, ddr_bist, _, atest_tsens2, atest_usb1, _, _), + PINGROUP(8, EAST, blsp_spi4, blsp_uart1_b, blsp_uim1_b, _, ddr_bist, _, wlan1_adc1, atest_usb13, bimc_dte1), + PINGROUP(9, EAST, blsp_spi4, blsp_uart1_b, blsp_uim1_b, tsif1_sync, ddr_bist, _, wlan1_adc0, atest_usb12, bimc_dte0), + PINGROUP(10, EAST, mdp_vsync_a, blsp_spi4, blsp_uart1_b, blsp_i2c4, ddr_bist, atest_gpsadc1, wlan2_adc1, atest_usb11, bimc_dte1), + PINGROUP(11, EAST, mdp_vsync_a, edp_lcd, blsp_spi4, blsp_uart1_b, blsp_i2c4, dbg_out, atest_gpsadc0, wlan2_adc0, atest_usb10), + PINGROUP(12, EAST, mdp_vsync, m_voc, _, _, _, _, _, _, _), + PINGROUP(13, EAST, cam_mclk, pll_bypassnl, qdss, _, _, _, _, _, _), + PINGROUP(14, EAST, cam_mclk, pll_reset, qdss, _, _, _, _, _, _), + PINGROUP(15, EAST, cam_mclk, qdss, _, _, _, _, _, _, _), + PINGROUP(16, EAST, cam_mclk, qdss, _, _, _, _, _, _, _), + PINGROUP(17, EAST, cci_i2c, qdss, _, _, _, _, _, _, _), + PINGROUP(18, EAST, cci_i2c, phase_flag, qdss, _, _, _, _, _, _), + PINGROUP(19, EAST, cci_i2c, phase_flag, qdss, _, _, _, _, _, _), + PINGROUP(20, EAST, cci_i2c, qdss, _, _, _, _, _, _, _), + PINGROUP(21, EAST, cci_timer0, _, qdss, vsense_data0, _, _, _, _, _), + PINGROUP(22, EAST, cci_timer1, _, qdss, vsense_data1, _, _, _, _, _), + PINGROUP(23, EAST, cci_timer2, blsp1_spi_b, qdss, vsense_mode, _, _, _, _, _), + PINGROUP(24, EAST, cci_timer3, cci_async, blsp1_spi_a, _, qdss, vsense_clkout, _, _, _), + PINGROUP(25, EAST, cci_timer4, cci_async, blsp2_spi, _, qdss, _, _, _, _), + PINGROUP(26, EAST, cci_async, qdss, _, _, _, _, _, _, _), + PINGROUP(27, EAST, blsp1_spi_a, qdss, _, _, _, _, _, _, _), + PINGROUP(28, EAST, blsp1_spi_b, qdss, _, _, _, _, _, _, _), + PINGROUP(29, EAST, blsp2_spi, _, qdss, _, _, _, _, _, _), + PINGROUP(30, EAST, hdmi_rcv, blsp2_spi, qdss, _, _, _, _, _, _), + PINGROUP(31, EAST, hdmi_cec, blsp_spi2, blsp_uart2_a, blsp_uim2_a, pwr_modem, _, _, _, _), + PINGROUP(32, EAST, hdmi_ddc, blsp_spi2, blsp_uart2_a, blsp_i2c2, pwr_nav, _, _, _, _), + PINGROUP(33, EAST, hdmi_ddc, blsp_spi2, blsp_uart2_a, blsp_i2c2, pwr_crypto, _, _, _, _), + PINGROUP(34, EAST, hdmi_hot, edp_hot, blsp_spi2, blsp_uart2_a, blsp_uim2_a, _, _, _, _), + PINGROUP(35, NORTH, pci_e0, jitter_bist, _, _, _, _, _, _, _), + PINGROUP(36, NORTH, pci_e0, agera_pll, _, atest_tsens, _, _, _, _, _), + PINGROUP(37, NORTH, agera_pll, _, _, _, _, _, _, _, _), + PINGROUP(38, WEST, usb_phy, _, _, _, _, _, _, _, _), + PINGROUP(39, WEST, lpass_slimbus, _, _, _, _, _, _, _, _), + PINGROUP(40, EAST, sd_write, tsif1_error, _, _, _, _, _, _, _), + PINGROUP(41, EAST, blsp_spi6, blsp_uart3_b, blsp_uim3_b, _, qdss, _, _, _, _), + PINGROUP(42, EAST, blsp_spi6, blsp_uart3_b, blsp_uim3_b, _, qdss, _, _, _, _), + PINGROUP(43, EAST, blsp_spi6, blsp_uart3_b, blsp_i2c6, _, qdss, _, _, _, _), + PINGROUP(44, EAST, blsp_spi6, blsp_uart3_b, blsp_i2c6, _, qdss, _, _, _, _), + PINGROUP(45, EAST, blsp_spi3, blsp_uart3_a, blsp_uim3_a, _, _, _, _, _, _), + PINGROUP(46, EAST, blsp_spi3, blsp_uart3_a, blsp_uim3_a, _, _, _, _, _, _), + PINGROUP(47, EAST, blsp_spi3, blsp_uart3_a, blsp_i2c3, _, _, _, _, _, _), + PINGROUP(48, EAST, blsp_spi3, blsp_uart3_a, blsp_i2c3, _, _, _, _, _, _), + PINGROUP(49, NORTH, blsp_spi9, blsp_uart9_a, blsp_uim9_a, blsp10_spi_b, qdss_cti0_a, _, _, _, _), + PINGROUP(50, NORTH, blsp_spi9, blsp_uart9_a, blsp_uim9_a, blsp10_spi_b, qdss_cti0_a, _, _, _, _), + PINGROUP(51, NORTH, blsp_spi9, blsp_uart9_a, blsp_i2c9, blsp10_spi_a, _, _, _, _, _), + PINGROUP(52, NORTH, blsp_spi9, blsp_uart9_a, blsp_i2c9, blsp10_spi_a, _, _, _, _, _), + PINGROUP(53, WEST, blsp_spi7, blsp_uart7_a, blsp_uim7_a, _, _, _, _, _, _), + PINGROUP(54, WEST, blsp_spi7, blsp_uart7_a, blsp_uim7_a, _, _, _, _, _, _), + PINGROUP(55, WEST, blsp_spi7, blsp_uart7_a, blsp_i2c7, _, _, _, _, _, _), + PINGROUP(56, WEST, blsp_spi7, blsp_uart7_a, blsp_i2c7, _, _, _, _, _, _), + PINGROUP(57, WEST, qua_mi2s, blsp10_spi, gcc_gp1_a, _, _, _, _, _, _), + PINGROUP(58, WEST, qua_mi2s, blsp_spi11, blsp_uart8_b, blsp_uim8_b, gcc_gp2_a, _, qdss_cti1_a, _, _), + PINGROUP(59, WEST, qua_mi2s, blsp_spi11, blsp_uart8_b, blsp_uim8_b, gcc_gp3_a, _, qdss_cti1_a, _, _), + PINGROUP(60, WEST, qua_mi2s, blsp_spi11, blsp_uart8_b, blsp_i2c11, cri_trng0, _, _, _, _), + PINGROUP(61, WEST, qua_mi2s, blsp_spi11, blsp_uart8_b, blsp_i2c11, cri_trng1, _, _, _, _), + PINGROUP(62, WEST, qua_mi2s, cri_trng, _, _, _, _, _, _, _), + PINGROUP(63, WEST, qua_mi2s, _, _, _, _, _, _, _, _), + PINGROUP(64, WEST, pri_mi2s, sp_cmu, _, _, _, _, _, _, _), + PINGROUP(65, WEST, pri_mi2s, blsp_spi10, blsp_uart7_b, blsp_uim7_b, _, _, _, _, _), + PINGROUP(66, WEST, pri_mi2s_ws, blsp_spi10, blsp_uart7_b, blsp_uim7_b, _, _, _, _, _), + PINGROUP(67, WEST, pri_mi2s, blsp_spi10, blsp_uart7_b, blsp_i2c10, _, _, _, _, _), + PINGROUP(68, WEST, pri_mi2s, blsp_spi10, blsp_uart7_b, blsp_i2c10, _, _, _, _, _), + PINGROUP(69, WEST, spkr_i2s, audio_ref, _, _, _, _, _, _, _), + PINGROUP(70, WEST, lpass_slimbus, spkr_i2s, blsp9_spi, _, _, _, _, _, _), + PINGROUP(71, WEST, lpass_slimbus, spkr_i2s, blsp9_spi, tsense_pwm1, tsense_pwm2, _, _, _, _), + PINGROUP(72, WEST, lpass_slimbus, spkr_i2s, blsp9_spi, _, _, _, _, _, _), + PINGROUP(73, WEST, btfm_slimbus, phase_flag, _, _, _, _, _, _, _), + PINGROUP(74, WEST, btfm_slimbus, ter_mi2s, phase_flag, _, _, _, _, _, _), + PINGROUP(75, WEST, ter_mi2s, phase_flag, qdss, _, _, _, _, _, _), + PINGROUP(76, WEST, ter_mi2s, phase_flag, qdss, _, _, _, _, _, _), + PINGROUP(77, WEST, ter_mi2s, phase_flag, qdss, _, _, _, _, _, _), + PINGROUP(78, WEST, ter_mi2s, gcc_gp1_b, _, _, _, _, _, _, _), + PINGROUP(79, WEST, sec_mi2s, _, qdss, _, _, _, _, _, _), + PINGROUP(80, WEST, sec_mi2s, _, qdss, _, _, _, _, _, _), + PINGROUP(81, WEST, sec_mi2s, blsp_spi12, blsp_uart9_b, blsp_uim9_b, gcc_gp2_b, _, _, _, _), + PINGROUP(82, WEST, sec_mi2s, blsp_spi12, blsp_uart9_b, blsp_uim9_b, gcc_gp3_b, _, _, _, _), + PINGROUP(83, WEST, sec_mi2s, blsp_spi12, blsp_uart9_b, blsp_i2c12, _, _, _, _, _), + PINGROUP(84, WEST, blsp_spi12, blsp_uart9_b, blsp_i2c12, _, _, _, _, _, _), + PINGROUP(85, EAST, blsp_spi5, blsp_uart2_b, blsp_uim2_b, _, _, _, _, _, _), + PINGROUP(86, EAST, blsp_spi5, blsp_uart2_b, blsp_uim2_b, _, _, _, _, _, _), + PINGROUP(87, EAST, blsp_spi5, blsp_uart2_b, blsp_i2c5, _, _, _, _, _, _), + PINGROUP(88, EAST, blsp_spi5, blsp_uart2_b, blsp_i2c5, _, _, _, _, _, _), + PINGROUP(89, EAST, tsif1_clk, phase_flag, _, _, _, _, _, _, _), + PINGROUP(90, EAST, tsif1_en, mdp_vsync0, mdp_vsync1, mdp_vsync2, mdp_vsync3, blsp1_spi, tgu_ch0, qdss_cti1_b, _), + PINGROUP(91, EAST, tsif1_data, sdc4_cmd, tgu_ch1, phase_flag, qdss_cti1_b, _, _, _, _), + PINGROUP(92, EAST, tsif2_error, sdc43, vfr_1, phase_flag, _, _, _, _, _), + PINGROUP(93, EAST, tsif2_clk, sdc4_clk, _, qdss, _, _, _, _, _), + PINGROUP(94, EAST, tsif2_en, sdc42, _, _, _, _, _, _, _), + PINGROUP(95, EAST, tsif2_data, sdc41, _, _, _, _, _, _, _), + PINGROUP(96, EAST, tsif2_sync, sdc40, phase_flag, _, _, _, _, _, _), + PINGROUP(97, WEST, _, mdp_vsync_b, ldo_en, _, _, _, _, _, _), + PINGROUP(98, WEST, _, mdp_vsync_b, ldo_update, _, _, _, _, _, _), + PINGROUP(99, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(100, WEST, _, _, blsp_uart8, _, _, _, _, _, _), + PINGROUP(101, WEST, _, blsp_uart8, _, _, _, _, _, _, _), + PINGROUP(102, WEST, _, blsp11_i2c, prng_rosc, _, _, _, _, _, _), + PINGROUP(103, WEST, _, blsp11_i2c, phase_flag, _, _, _, _, _, _), + PINGROUP(104, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(105, NORTH, uim2_data, _, _, _, _, _, _, _, _), + PINGROUP(106, NORTH, uim2_clk, _, _, _, _, _, _, _, _), + PINGROUP(107, NORTH, uim2_reset, _, _, _, _, _, _, _, _), + PINGROUP(108, NORTH, uim2_present, _, _, _, _, _, _, _, _), + PINGROUP(109, NORTH, uim1_data, _, _, _, _, _, _, _, _), + PINGROUP(110, NORTH, uim1_clk, _, _, _, _, _, _, _, _), + PINGROUP(111, NORTH, uim1_reset, _, _, _, _, _, _, _, _), + PINGROUP(112, NORTH, uim1_present, _, _, _, _, _, _, _, _), + PINGROUP(113, NORTH, uim_batt, _, _, _, _, _, _, _, _), + PINGROUP(114, WEST, _, _, phase_flag, _, _, _, _, _, _), + PINGROUP(115, WEST, _, nav_dr, phase_flag, _, _, _, _, _, _), + PINGROUP(116, WEST, phase_flag, _, _, _, _, _, _, _, _), + PINGROUP(117, EAST, phase_flag, qdss, atest_char, _, _, _, _, _, _), + PINGROUP(118, EAST, adsp_ext, phase_flag, qdss, atest_char, _, _, _, _, _), + PINGROUP(119, EAST, phase_flag, qdss, atest_char, _, _, _, _, _, _), + PINGROUP(120, EAST, phase_flag, qdss, atest_char, _, _, _, _, _, _), + PINGROUP(121, EAST, phase_flag, qdss, atest_char, _, _, _, _, _, _), + PINGROUP(122, EAST, phase_flag, qdss, _, _, _, _, _, _, _), + PINGROUP(123, EAST, phase_flag, qdss, _, _, _, _, _, _, _), + PINGROUP(124, EAST, phase_flag, qdss, _, _, _, _, _, _, _), + PINGROUP(125, EAST, phase_flag, _, _, _, _, _, _, _, _), + PINGROUP(126, EAST, phase_flag, _, _, _, _, _, _, _, _), + PINGROUP(127, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(128, WEST, modem_tsync, nav_pps, phase_flag, _, _, _, _, _, _), + PINGROUP(129, WEST, phase_flag, _, _, _, _, _, _, _, _), + PINGROUP(130, NORTH, qlink_request, phase_flag, _, _, _, _, _, _, _), + PINGROUP(131, NORTH, qlink_enable, phase_flag, _, _, _, _, _, _, _), + PINGROUP(132, WEST, _, phase_flag, _, _, _, _, _, _, _), + PINGROUP(133, WEST, phase_flag, _, _, _, _, _, _, _, _), + PINGROUP(134, WEST, phase_flag, _, _, _, _, _, _, _, _), + PINGROUP(135, WEST, _, pa_indicator, _, _, _, _, _, _, _), + PINGROUP(136, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(137, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(138, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(139, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(140, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(141, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(142, WEST, _, ssbi1, _, _, _, _, _, _, _), + PINGROUP(143, WEST, isense_dbg, _, _, _, _, _, _, _, _), + PINGROUP(144, WEST, mss_lte, _, _, _, _, _, _, _, _), + PINGROUP(145, WEST, mss_lte, _, _, _, _, _, _, _, _), + PINGROUP(146, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(147, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(148, WEST, _, _, _, _, _, _, _, _, _), + PINGROUP(149, WEST, _, _, _, _, _, _, _, _, _), + SDC_QDSD_PINGROUP(sdc2_clk, 0x999000, 14, 6), + SDC_QDSD_PINGROUP(sdc2_cmd, 0x999000, 11, 3), + SDC_QDSD_PINGROUP(sdc2_data, 0x999000, 9, 0), + UFS_RESET(ufs_reset, 0x19d000), +}; + +static const struct msm_pinctrl_soc_data msm8998_pinctrl = { + .pins = msm8998_pins, + .npins = ARRAY_SIZE(msm8998_pins), + .functions = msm8998_functions, + .nfunctions = ARRAY_SIZE(msm8998_functions), + .groups = msm8998_groups, + .ngroups = ARRAY_SIZE(msm8998_groups), + .ngpios = 150, +}; + +static int msm8998_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &msm8998_pinctrl); +} + +static const struct of_device_id msm8998_pinctrl_of_match[] = { + { .compatible = "qcom,msm8998-pinctrl", }, + { }, +}; + +static struct platform_driver msm8998_pinctrl_driver = { + .driver = { + .name = "msm8998-pinctrl", + .owner = THIS_MODULE, + .of_match_table = msm8998_pinctrl_of_match, + }, + .probe = msm8998_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init msm8998_pinctrl_init(void) +{ + return platform_driver_register(&msm8998_pinctrl_driver); +} +arch_initcall(msm8998_pinctrl_init); + +static void __exit msm8998_pinctrl_exit(void) +{ + platform_driver_unregister(&msm8998_pinctrl_driver); +} +module_exit(msm8998_pinctrl_exit); + +MODULE_DESCRIPTION("QTI msm8998 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, msm8998_pinctrl_of_match); -- cgit From 4f0ceb878920cd0ac862f0f3eb08e4c4e3aa12ee Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Sat, 2 Dec 2017 04:22:45 -0600 Subject: mailbox: ti-msgmgr: Switch to SPDX Licensing Switch to SPDX licensing and drop the GPL text which comes redundant. Signed-off-by: Nishanth Menon Signed-off-by: Jassi Brar --- drivers/mailbox/ti-msgmgr.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index 54b9e4cb4cfa..c8f34d69f03c 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Texas Instruments' Message Manager Driver * - * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ * Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define pr_fmt(fmt) "%s: " fmt, __func__ -- cgit From ca64af43924f85d5de1b384709af3a3ea8c7ebbb Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Sat, 2 Dec 2017 04:27:18 -0600 Subject: mailbox: ti-msgmgr: Use %zu for size_t print format message->len is of type size_t and %d is incorrect format usage. Instead use %zu for handling size_t correctly. Signed-off-by: Nishanth Menon Signed-off-by: Jassi Brar --- drivers/mailbox/ti-msgmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index c8f34d69f03c..78753a87ba4d 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -283,7 +283,7 @@ static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data) desc = inst->desc; if (desc->max_message_size < message->len) { - dev_err(dev, "Queue %s message length %d > max %d\n", + dev_err(dev, "Queue %s message length %zu > max %d\n", qinst->name, message->len, desc->max_message_size); return -EINVAL; } -- cgit From 32e21f084faacc69014b4bb082db04890fad5f1b Mon Sep 17 00:00:00 2001 From: hao_zhang Date: Tue, 9 Jan 2018 13:59:02 +0800 Subject: pinctrl: sunxi-pinctrl: fix pin funtion can not be match correctly. Pin function can not be match correctly when SUNXI_PIN describe with mutiple variant and same function. such as: on pinctrl-sun4i-a10.c SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), SUNXI_FUNCTION(0x0, "gpio_in"), SUNXI_FUNCTION(0x1, "gpio_out"), SUNXI_FUNCTION_VARIANT(0x2, "pwm", /* PWM0 */ PINCTRL_SUN4I_A10 | PINCTRL_SUN7I_A20), SUNXI_FUNCTION_VARIANT(0x3, "pwm", /* PWM0 */ PINCTRL_SUN8I_R40)), it would always match to the first variant function (PINCTRL_SUN4I_A10, PINCTRL_SUN7I_A20) so we should add variant compare on it. Signed-off-by: hao_zhang Acked-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 4b6cb25bc796..131adf7953cd 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -83,7 +83,9 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, struct sunxi_desc_function *func = pin->functions; while (func->name) { - if (!strcmp(func->name, func_name)) + if (!strcmp(func->name, func_name) && + (!func->variant || + func->variant & pctl->variant)) return func; func++; -- cgit From f5843492ecefcf766963518f14bcf8d77b88338c Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 6 Jan 2018 15:25:49 +0100 Subject: pinctrl: imx: use struct imx_pinctrl_soc_info as a const For some SoCs the struct imx_pinctrl_soc_info is passed through of_device_id.data which is const. Most variables are already const or otherwise not written. However, some fields are modified at runtime. Move those fields to the dynamically allocated struct imx_pinctrl. Fixes: b3060044e495 ("pinctrl: freescale: imx7d: make of_device_ids const") Cc: Shawn Guo Cc: Arvind Yadav Cc: Gary Bisson Signed-off-by: Stefan Agner Acked-by: Dong Aisheng Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx.c | 79 ++++++++++++++--------------- drivers/pinctrl/freescale/pinctrl-imx.h | 11 ++-- drivers/pinctrl/freescale/pinctrl-imx7ulp.c | 3 +- drivers/pinctrl/freescale/pinctrl-vf610.c | 3 +- 4 files changed, 44 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 6e472691d8ee..86256d25c4a3 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -62,7 +62,6 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned *num_maps) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; const struct group_desc *grp; struct pinctrl_map *new_map; struct device_node *parent; @@ -75,7 +74,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, */ grp = imx_pinctrl_find_group_by_name(pctldev, np->name); if (!grp) { - dev_err(info->dev, "unable to find group for node %s\n", + dev_err(ipctl->dev, "unable to find group for node %s\n", np->name); return -EINVAL; } @@ -146,7 +145,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; unsigned int npins, pin_id; int i; @@ -174,7 +173,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; pin_id = pin->pin; - pin_reg = &info->pin_regs[pin_id]; + pin_reg = &ipctl->pin_regs[pin_id]; if (pin_reg->mux_reg == -1) { dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n", @@ -255,7 +254,7 @@ static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl, unsigned long *configs, unsigned int num_configs) { - struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pinctrl_soc_info *info = ipctl->info; struct imx_cfg_params_decode *decode; enum pin_config_param param; u32 raw_config = 0; @@ -289,7 +288,7 @@ static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl, static u32 imx_pinconf_parse_generic_config(struct device_node *np, struct imx_pinctrl *ipctl) { - struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pinctrl_soc_info *info = ipctl->info; struct pinctrl_dev *pctl = ipctl->pctl; unsigned int num_configs; unsigned long *configs; @@ -310,11 +309,11 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin_id, unsigned long *config) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id]; if (pin_reg->conf_reg == -1) { - dev_err(info->dev, "Pin(%s) does not support config function\n", + dev_err(ipctl->dev, "Pin(%s) does not support config function\n", info->pins[pin_id].name); return -EINVAL; } @@ -332,12 +331,12 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, unsigned num_configs) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id]; int i; if (pin_reg->conf_reg == -1) { - dev_err(info->dev, "Pin(%s) does not support config function\n", + dev_err(ipctl->dev, "Pin(%s) does not support config function\n", info->pins[pin_id].name); return -EINVAL; } @@ -368,8 +367,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin_id) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; - const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; + const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id]; unsigned long config; if (!pin_reg || pin_reg->conf_reg == -1) { @@ -427,13 +425,13 @@ static int imx_pinctrl_parse_groups(struct device_node *np, struct imx_pinctrl *ipctl, u32 index) { - struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pinctrl_soc_info *info = ipctl->info; int size, pin_size; const __be32 *list; int i; u32 config; - dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + dev_dbg(ipctl->dev, "group(%d): %s\n", index, np->name); if (info->flags & SHARE_MUX_CONF_REG) pin_size = SHARE_FSL_PIN_SIZE; @@ -460,7 +458,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, if (!list) { list = of_get_property(np, "pinmux", &size); if (!list) { - dev_err(info->dev, + dev_err(ipctl->dev, "no fsl,pins and pins property in node %pOF\n", np); return -EINVAL; } @@ -468,7 +466,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, /* we do not check return since it's safe node passed down */ if (!size || size % pin_size) { - dev_err(info->dev, "Invalid fsl,pins or pins property in node %pOF\n", np); + dev_err(ipctl->dev, "Invalid fsl,pins or pins property in node %pOF\n", np); return -EINVAL; } @@ -476,9 +474,9 @@ static int imx_pinctrl_parse_groups(struct device_node *np, config = imx_pinconf_parse_generic_config(np, ipctl); grp->num_pins = size / pin_size; - grp->data = devm_kzalloc(info->dev, grp->num_pins * + grp->data = devm_kzalloc(ipctl->dev, grp->num_pins * sizeof(struct imx_pin), GFP_KERNEL); - grp->pins = devm_kzalloc(info->dev, grp->num_pins * + grp->pins = devm_kzalloc(ipctl->dev, grp->num_pins * sizeof(unsigned int), GFP_KERNEL); if (!grp->pins || !grp->data) return -ENOMEM; @@ -502,7 +500,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, } pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4; - pin_reg = &info->pin_regs[pin_id]; + pin_reg = &ipctl->pin_regs[pin_id]; pin->pin = pin_id; grp->pins[i] = pin_id; pin_reg->mux_reg = mux_reg; @@ -524,7 +522,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, pin->config = config & ~IMX_PAD_SION; } - dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name, + dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name, pin->mux_mode, pin->config); } @@ -536,13 +534,12 @@ static int imx_pinctrl_parse_functions(struct device_node *np, u32 index) { struct pinctrl_dev *pctl = ipctl->pctl; - struct imx_pinctrl_soc_info *info = ipctl->info; struct device_node *child; struct function_desc *func; struct group_desc *grp; u32 i = 0; - dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + dev_dbg(pctl->dev, "parse function(%d): %s\n", index, np->name); func = pinmux_generic_get_function(pctl, index); if (!func) @@ -552,10 +549,10 @@ static int imx_pinctrl_parse_functions(struct device_node *np, func->name = np->name; func->num_group_names = of_get_child_count(np); if (func->num_group_names == 0) { - dev_err(info->dev, "no groups defined in %pOF\n", np); + dev_err(ipctl->dev, "no groups defined in %pOF\n", np); return -EINVAL; } - func->group_names = devm_kcalloc(info->dev, func->num_group_names, + func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names, sizeof(char *), GFP_KERNEL); if (!func->group_names) return -ENOMEM; @@ -563,15 +560,15 @@ static int imx_pinctrl_parse_functions(struct device_node *np, for_each_child_of_node(np, child) { func->group_names[i] = child->name; - grp = devm_kzalloc(info->dev, sizeof(struct group_desc), + grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc), GFP_KERNEL); if (!grp) return -ENOMEM; - mutex_lock(&info->mutex); + mutex_lock(&ipctl->mutex); radix_tree_insert(&pctl->pin_group_tree, - info->group_index++, grp); - mutex_unlock(&info->mutex); + ipctl->group_index++, grp); + mutex_unlock(&ipctl->mutex); imx_pinctrl_parse_groups(child, grp, ipctl, i++); } @@ -608,7 +605,6 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, struct device_node *np = pdev->dev.of_node; struct device_node *child; struct pinctrl_dev *pctl = ipctl->pctl; - struct imx_pinctrl_soc_info *info = ipctl->info; u32 nfuncs = 0; u32 i = 0; bool flat_funcs; @@ -635,13 +631,13 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, if (!function) return -ENOMEM; - mutex_lock(&info->mutex); + mutex_lock(&ipctl->mutex); radix_tree_insert(&pctl->pin_function_tree, i, function); - mutex_unlock(&info->mutex); + mutex_unlock(&ipctl->mutex); } pctl->num_functions = nfuncs; - info->group_index = 0; + ipctl->group_index = 0; if (flat_funcs) { pctl->num_groups = of_get_child_count(np); } else { @@ -672,7 +668,7 @@ static void imx_free_resources(struct imx_pinctrl *ipctl) } int imx_pinctrl_probe(struct platform_device *pdev, - struct imx_pinctrl_soc_info *info) + const struct imx_pinctrl_soc_info *info) { struct regmap_config config = { .name = "gpr" }; struct device_node *dev_np = pdev->dev.of_node; @@ -687,7 +683,6 @@ int imx_pinctrl_probe(struct platform_device *pdev, dev_err(&pdev->dev, "wrong pinctrl info\n"); return -EINVAL; } - info->dev = &pdev->dev; if (info->gpr_compatible) { gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible); @@ -700,14 +695,14 @@ int imx_pinctrl_probe(struct platform_device *pdev, if (!ipctl) return -ENOMEM; - info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) * + ipctl->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*ipctl->pin_regs) * info->npins, GFP_KERNEL); - if (!info->pin_regs) + if (!ipctl->pin_regs) return -ENOMEM; for (i = 0; i < info->npins; i++) { - info->pin_regs[i].mux_reg = -1; - info->pin_regs[i].conf_reg = -1; + ipctl->pin_regs[i].mux_reg = -1; + ipctl->pin_regs[i].conf_reg = -1; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -751,10 +746,10 @@ int imx_pinctrl_probe(struct platform_device *pdev, /* platform specific callback */ imx_pmx_ops.gpio_set_direction = info->gpio_set_direction; - mutex_init(&info->mutex); + mutex_init(&ipctl->mutex); ipctl->info = info; - ipctl->dev = info->dev; + ipctl->dev = &pdev->dev; platform_set_drvdata(pdev, ipctl); ret = devm_pinctrl_register_and_init(&pdev->dev, imx_pinctrl_desc, ipctl, diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index 5aa22b52c1d4..41ee75537da4 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -58,14 +58,10 @@ struct imx_cfg_params_decode { }; struct imx_pinctrl_soc_info { - struct device *dev; const struct pinctrl_pin_desc *pins; unsigned int npins; - struct imx_pin_reg *pin_regs; - unsigned int group_index; unsigned int flags; const char *gpr_compatible; - struct mutex mutex; /* MUX_MODE shift and mask in case SHARE_MUX_CONF_REG */ unsigned int mux_mask; @@ -95,7 +91,10 @@ struct imx_pinctrl { struct pinctrl_dev *pctl; void __iomem *base; void __iomem *input_sel_base; - struct imx_pinctrl_soc_info *info; + const struct imx_pinctrl_soc_info *info; + struct imx_pin_reg *pin_regs; + unsigned int group_index; + struct mutex mutex; }; #define IMX_CFG_PARAMS_DECODE(p, m, o) \ @@ -117,5 +116,5 @@ struct imx_pinctrl { #define IOMUXC_CONFIG_SION (0x1 << 4) int imx_pinctrl_probe(struct platform_device *pdev, - struct imx_pinctrl_soc_info *info); + const struct imx_pinctrl_soc_info *info); #endif /* __DRIVERS_PINCTRL_IMX_H */ diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c index b7bebb292f37..9161c984f57b 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c +++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c @@ -307,11 +307,10 @@ static int imx7ulp_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, unsigned offset, bool input) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; u32 reg; - pin_reg = &info->pin_regs[offset]; + pin_reg = &ipctl->pin_regs[offset]; if (pin_reg->mux_reg == -1) return -EINVAL; diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c index ac18bb6d6d5e..42745c690be3 100644 --- a/drivers/pinctrl/freescale/pinctrl-vf610.c +++ b/drivers/pinctrl/freescale/pinctrl-vf610.c @@ -300,11 +300,10 @@ static int vf610_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, unsigned offset, bool input) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; u32 reg; - pin_reg = &info->pin_regs[offset]; + pin_reg = &ipctl->pin_regs[offset]; if (pin_reg->mux_reg == -1) return -EINVAL; -- cgit From 7372077542b0d5b6a1ed68493e5758045119cedd Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 6 Jan 2018 15:25:50 +0100 Subject: pinctrl: imx7d: simplify imx7d_pinctrl_probe Using of_device_get_match_data in imx7d_pinctrl_probe simplifies the function. Also get rid of the void pointer cast since imx_pinctrl_probe now accepts const struct imx_pinctrl_soc_info. Cc: Arvind Yadav Signed-off-by: Stefan Agner Acked-by: Dong Aisheng Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx7d.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/pinctrl-imx7d.c b/drivers/pinctrl/freescale/pinctrl-imx7d.c index 754159ee7b1e..0b0a2f33b06a 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx7d.c +++ b/drivers/pinctrl/freescale/pinctrl-imx7d.c @@ -378,16 +378,12 @@ static const struct of_device_id imx7d_pinctrl_of_match[] = { static int imx7d_pinctrl_probe(struct platform_device *pdev) { - const struct of_device_id *match; - struct imx_pinctrl_soc_info *pinctrl_info; + const struct imx_pinctrl_soc_info *pinctrl_info; - match = of_match_device(imx7d_pinctrl_of_match, &pdev->dev); - - if (!match) + pinctrl_info = of_device_get_match_data(&pdev->dev); + if (!pinctrl_info) return -ENODEV; - pinctrl_info = (struct imx_pinctrl_soc_info *) match->data; - return imx_pinctrl_probe(pdev, pinctrl_info); } -- cgit From 7c017687f8103067e66103744ce76ae92e0a40f5 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 6 Jan 2018 15:25:51 +0100 Subject: pinctrl: imx: constify struct imx_pinctrl_soc_info Now that imx_pinctrl_probe accepts const struct imx_pinctrl_soc_info we can constify all declarations of struct imx_pinctrl_soc_info. Signed-off-by: Stefan Agner Acked-by: Dong Aisheng Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx25.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx35.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx50.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx51.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx53.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx6dl.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx6q.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx6sl.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx6sx.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx7ulp.c | 2 +- drivers/pinctrl/freescale/pinctrl-vf610.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/pinctrl-imx25.c b/drivers/pinctrl/freescale/pinctrl-imx25.c index d7367fabe712..db6d9d1382f9 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx25.c +++ b/drivers/pinctrl/freescale/pinctrl-imx25.c @@ -309,7 +309,7 @@ static const struct pinctrl_pin_desc imx25_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX25_PAD_BOOT_MODE1), }; -static struct imx_pinctrl_soc_info imx25_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx25_pinctrl_info = { .pins = imx25_pinctrl_pads, .npins = ARRAY_SIZE(imx25_pinctrl_pads), }; diff --git a/drivers/pinctrl/freescale/pinctrl-imx35.c b/drivers/pinctrl/freescale/pinctrl-imx35.c index 6315ba6af431..6927946ae4b5 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx35.c +++ b/drivers/pinctrl/freescale/pinctrl-imx35.c @@ -999,7 +999,7 @@ static const struct pinctrl_pin_desc imx35_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX35_PAD_TEST_MODE), }; -static struct imx_pinctrl_soc_info imx35_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx35_pinctrl_info = { .pins = imx35_pinctrl_pads, .npins = ARRAY_SIZE(imx35_pinctrl_pads), }; diff --git a/drivers/pinctrl/freescale/pinctrl-imx50.c b/drivers/pinctrl/freescale/pinctrl-imx50.c index 8e3a17df5c5d..eb349b97290f 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx50.c +++ b/drivers/pinctrl/freescale/pinctrl-imx50.c @@ -385,7 +385,7 @@ static const struct pinctrl_pin_desc imx50_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX50_PAD_EIM_CRE), }; -static struct imx_pinctrl_soc_info imx50_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx50_pinctrl_info = { .pins = imx50_pinctrl_pads, .npins = ARRAY_SIZE(imx50_pinctrl_pads), .gpr_compatible = "fsl,imx50-iomuxc-gpr", diff --git a/drivers/pinctrl/freescale/pinctrl-imx51.c b/drivers/pinctrl/freescale/pinctrl-imx51.c index eeac64ba2709..49acd991b5fb 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx51.c +++ b/drivers/pinctrl/freescale/pinctrl-imx51.c @@ -762,7 +762,7 @@ static const struct pinctrl_pin_desc imx51_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX51_PAD_CSI1_MCLK), }; -static struct imx_pinctrl_soc_info imx51_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx51_pinctrl_info = { .pins = imx51_pinctrl_pads, .npins = ARRAY_SIZE(imx51_pinctrl_pads), }; diff --git a/drivers/pinctrl/freescale/pinctrl-imx53.c b/drivers/pinctrl/freescale/pinctrl-imx53.c index 46a9572f3473..6dd0c60eaea4 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx53.c +++ b/drivers/pinctrl/freescale/pinctrl-imx53.c @@ -448,7 +448,7 @@ static const struct pinctrl_pin_desc imx53_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX53_PAD_GPIO_18), }; -static struct imx_pinctrl_soc_info imx53_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx53_pinctrl_info = { .pins = imx53_pinctrl_pads, .npins = ARRAY_SIZE(imx53_pinctrl_pads), .gpr_compatible = "fsl,imx53-iomuxc-gpr", diff --git a/drivers/pinctrl/freescale/pinctrl-imx6dl.c b/drivers/pinctrl/freescale/pinctrl-imx6dl.c index 3f25ca5867cc..91b85fc01de8 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6dl.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6dl.c @@ -457,7 +457,7 @@ static const struct pinctrl_pin_desc imx6dl_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX6DL_PAD_SD4_DAT7), }; -static struct imx_pinctrl_soc_info imx6dl_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx6dl_pinctrl_info = { .pins = imx6dl_pinctrl_pads, .npins = ARRAY_SIZE(imx6dl_pinctrl_pads), .gpr_compatible = "fsl,imx6q-iomuxc-gpr", diff --git a/drivers/pinctrl/freescale/pinctrl-imx6q.c b/drivers/pinctrl/freescale/pinctrl-imx6q.c index d61651c40458..5f653d69d0f5 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6q.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6q.c @@ -460,7 +460,7 @@ static const struct pinctrl_pin_desc imx6q_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT3), }; -static struct imx_pinctrl_soc_info imx6q_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx6q_pinctrl_info = { .pins = imx6q_pinctrl_pads, .npins = ARRAY_SIZE(imx6q_pinctrl_pads), .gpr_compatible = "fsl,imx6q-iomuxc-gpr", diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sl.c b/drivers/pinctrl/freescale/pinctrl-imx6sl.c index d023f6b00623..1167dc273c04 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6sl.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6sl.c @@ -363,7 +363,7 @@ static const struct pinctrl_pin_desc imx6sl_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX6SL_PAD_WDOG_B), }; -static struct imx_pinctrl_soc_info imx6sl_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx6sl_pinctrl_info = { .pins = imx6sl_pinctrl_pads, .npins = ARRAY_SIZE(imx6sl_pinctrl_pads), .gpr_compatible = "fsl,imx6sl-iomuxc-gpr", diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sx.c b/drivers/pinctrl/freescale/pinctrl-imx6sx.c index 898b781701e6..15ea56c75f68 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6sx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6sx.c @@ -367,7 +367,7 @@ static const struct pinctrl_pin_desc imx6sx_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX6SX_PAD_USB_H_STROBE), }; -static struct imx_pinctrl_soc_info imx6sx_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx6sx_pinctrl_info = { .pins = imx6sx_pinctrl_pads, .npins = ARRAY_SIZE(imx6sx_pinctrl_pads), .gpr_compatible = "fsl,imx6sx-iomuxc-gpr", diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c index 9161c984f57b..0406d8b39e6a 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c +++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c @@ -324,7 +324,7 @@ static int imx7ulp_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, return 0; } -static struct imx_pinctrl_soc_info imx7ulp_pinctrl_info = { +static const struct imx_pinctrl_soc_info imx7ulp_pinctrl_info = { .pins = imx7ulp_pinctrl_pads, .npins = ARRAY_SIZE(imx7ulp_pinctrl_pads), .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG, diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c index 42745c690be3..c078f859ae15 100644 --- a/drivers/pinctrl/freescale/pinctrl-vf610.c +++ b/drivers/pinctrl/freescale/pinctrl-vf610.c @@ -318,7 +318,7 @@ static int vf610_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, return 0; } -static struct imx_pinctrl_soc_info vf610_pinctrl_info = { +static const struct imx_pinctrl_soc_info vf610_pinctrl_info = { .pins = vf610_pinctrl_pads, .npins = ARRAY_SIZE(vf610_pinctrl_pads), .flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID, -- cgit From d6093367bc743bc6679ab75a89cd3dd93476a755 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 6 Jan 2018 15:25:52 +0100 Subject: pinctrl: imx7ulp: constify struct imx_cfg_params_decode The decode parameters are constant mark them const. Signed-off-by: Stefan Agner Acked-by: Dong Aisheng Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx.c | 2 +- drivers/pinctrl/freescale/pinctrl-imx.h | 2 +- drivers/pinctrl/freescale/pinctrl-imx7ulp.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 86256d25c4a3..24aaddd760a0 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -255,7 +255,7 @@ static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl, unsigned int num_configs) { const struct imx_pinctrl_soc_info *info = ipctl->info; - struct imx_cfg_params_decode *decode; + const struct imx_cfg_params_decode *decode; enum pin_config_param param; u32 raw_config = 0; u32 param_val; diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index 41ee75537da4..038e8c0e5b96 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -71,7 +71,7 @@ struct imx_pinctrl_soc_info { bool generic_pinconf; const struct pinconf_generic_params *custom_params; unsigned int num_custom_params; - struct imx_cfg_params_decode *decodes; + const struct imx_cfg_params_decode *decodes; unsigned int num_decodes; void (*fixup)(unsigned long *configs, unsigned int num_configs, u32 *raw_config); diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c index 0406d8b39e6a..f363e45fd246 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c +++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c @@ -266,7 +266,7 @@ static const struct pinctrl_pin_desc imx7ulp_pinctrl_pads[] = { #define BP_MUX_MODE 8 #define BM_PULL_ENABLED BIT(1) -struct imx_cfg_params_decode imx7ulp_cfg_decodes[] = { +static const struct imx_cfg_params_decode imx7ulp_cfg_decodes[] = { IMX_CFG_PARAMS_DECODE(PIN_CONFIG_DRIVE_STRENGTH, BIT(6), 6), IMX_CFG_PARAMS_DECODE(PIN_CONFIG_DRIVE_PUSH_PULL, BIT(5), 5), IMX_CFG_PARAMS_DECODE(PIN_CONFIG_SLEW_RATE, BIT(2), 2), -- cgit From fb36a7b07dbf565014ed624a1bfd24d807f56b85 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 10 Jan 2018 17:34:14 +0900 Subject: pinctrl: uniphier: refactor drive strength get/set functions There is code duplication between uniphier_conf_pin_drive_get() and uniphier_conf_pin_drive_set(). Factor out the common code into uniphier_conf_get_drvctrl_data(). Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/pinctrl-uniphier-core.c | 176 ++++++++++++----------- 1 file changed, 91 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c index 26fda5c53e65..ec0f77afeaa4 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c @@ -146,6 +146,71 @@ static const struct pinctrl_ops uniphier_pctlops = { .dt_free_map = pinctrl_utils_free_map, }; +static const unsigned int uniphier_conf_drv_strengths_1bit[] = {4, 8}; +static const unsigned int uniphier_conf_drv_strengths_2bit[] = {8, 12, 16, 20}; +static const unsigned int uniphier_conf_drv_strengths_3bit[] = {4, 5, 7, 9, 11, + 12, 14, 16}; +static const unsigned int uniphier_conf_drv_strengths_fixed4[] = {4}; +static const unsigned int uniphier_conf_drv_strengths_fixed5[] = {5}; +static const unsigned int uniphier_conf_drv_strengths_fixed8[] = {8}; + +static int uniphier_conf_get_drvctrl_data(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned int *reg, + unsigned int *shift, + unsigned int *mask, + const unsigned int **strengths) +{ + const struct pin_desc *desc = pin_desc_get(pctldev, pin); + enum uniphier_pin_drv_type type = + uniphier_pin_get_drv_type(desc->drv_data); + unsigned int base = 0; + unsigned int stride = 0; + unsigned int width = 0; + unsigned int drvctrl; + + switch (type) { + case UNIPHIER_PIN_DRV_1BIT: + *strengths = uniphier_conf_drv_strengths_1bit; + base = UNIPHIER_PINCTRL_DRVCTRL_BASE; + stride = 1; + width = 1; + break; + case UNIPHIER_PIN_DRV_2BIT: + *strengths = uniphier_conf_drv_strengths_2bit; + base = UNIPHIER_PINCTRL_DRV2CTRL_BASE; + stride = 2; + width = 2; + break; + case UNIPHIER_PIN_DRV_3BIT: + *strengths = uniphier_conf_drv_strengths_3bit; + base = UNIPHIER_PINCTRL_DRV3CTRL_BASE; + stride = 4; + width = 3; + break; + case UNIPHIER_PIN_DRV_FIXED4: + *strengths = uniphier_conf_drv_strengths_fixed4; + break; + case UNIPHIER_PIN_DRV_FIXED5: + *strengths = uniphier_conf_drv_strengths_fixed5; + break; + case UNIPHIER_PIN_DRV_FIXED8: + *strengths = uniphier_conf_drv_strengths_fixed8; + break; + default: + /* drive strength control is not supported for this pin */ + return -EINVAL; + } + + drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); + drvctrl *= stride; + + *reg = base + drvctrl / 32 * 4; + *shift = drvctrl % 32; + *mask = (1U << width) - 1; + + return 0; +} + static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, unsigned int pin, enum pin_config_param param) @@ -201,59 +266,24 @@ static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, unsigned int pin, u32 *strength) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); - const struct pin_desc *desc = pin_desc_get(pctldev, pin); - enum uniphier_pin_drv_type type = - uniphier_pin_get_drv_type(desc->drv_data); - static const unsigned int strength_1bit[] = {4, 8}; - static const unsigned int strength_2bit[] = {8, 12, 16, 20}; - static const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, - 14, 16}; - const unsigned int *supported_strength; - unsigned int drvctrl, reg, shift, mask, width, val; + unsigned int reg, shift, mask, val; + const unsigned int *strengths; int ret; - switch (type) { - case UNIPHIER_PIN_DRV_1BIT: - supported_strength = strength_1bit; - reg = UNIPHIER_PINCTRL_DRVCTRL_BASE; - width = 1; - break; - case UNIPHIER_PIN_DRV_2BIT: - supported_strength = strength_2bit; - reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE; - width = 2; - break; - case UNIPHIER_PIN_DRV_3BIT: - supported_strength = strength_3bit; - reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE; - width = 4; - break; - case UNIPHIER_PIN_DRV_FIXED4: - *strength = 4; - return 0; - case UNIPHIER_PIN_DRV_FIXED5: - *strength = 5; - return 0; - case UNIPHIER_PIN_DRV_FIXED8: - *strength = 8; - return 0; - default: - /* drive strength control is not supported for this pin */ - return -EINVAL; - } - - drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); - drvctrl *= width; - - reg += drvctrl / 32 * 4; - shift = drvctrl % 32; - mask = (1U << width) - 1; - - ret = regmap_read(priv->regmap, reg, &val); + ret = uniphier_conf_get_drvctrl_data(pctldev, pin, ®, &shift, + &mask, &strengths); if (ret) return ret; - *strength = supported_strength[(val >> shift) & mask]; + if (mask) { + ret = regmap_read(priv->regmap, reg, &val); + if (ret) + return ret; + } else { + val = 0; + } + + *strength = strengths[(val >> shift) & mask]; return 0; } @@ -398,40 +428,20 @@ static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); const struct pin_desc *desc = pin_desc_get(pctldev, pin); - enum uniphier_pin_drv_type type = - uniphier_pin_get_drv_type(desc->drv_data); - static const unsigned int strength_1bit[] = {4, 8, -1}; - static const unsigned int strength_2bit[] = {8, 12, 16, 20, -1}; - static const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, - 16, -1}; - const unsigned int *supported_strength; - unsigned int drvctrl, reg, shift, mask, width, val; + unsigned int reg, shift, mask, val; + const unsigned int *strengths; + int ret; - switch (type) { - case UNIPHIER_PIN_DRV_1BIT: - supported_strength = strength_1bit; - reg = UNIPHIER_PINCTRL_DRVCTRL_BASE; - width = 1; - break; - case UNIPHIER_PIN_DRV_2BIT: - supported_strength = strength_2bit; - reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE; - width = 2; - break; - case UNIPHIER_PIN_DRV_3BIT: - supported_strength = strength_3bit; - reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE; - width = 4; - break; - default: - dev_err(pctldev->dev, - "cannot change drive strength for pin %s\n", + ret = uniphier_conf_get_drvctrl_data(pctldev, pin, ®, &shift, + &mask, &strengths); + if (ret) { + dev_err(pctldev->dev, "cannot set drive strength for pin %s\n", desc->name); - return -EINVAL; + return ret; } - for (val = 0; supported_strength[val] > 0; val++) { - if (supported_strength[val] > strength) + for (val = 0; val <= mask; val++) { + if (strengths[val] > strength) break; } @@ -442,14 +452,10 @@ static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, return -EINVAL; } - val--; - - drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); - drvctrl *= width; + if (!mask) + return 0; - reg += drvctrl / 32 * 4; - shift = drvctrl % 32; - mask = (1U << width) - 1; + val--; return regmap_update_bits(priv->regmap, reg, mask << shift, val << shift); -- cgit From 181cdac02c51a77f9ae497be624edb99056a0a10 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 10 Jan 2018 00:28:24 +0800 Subject: pinctrl: mediatek: mt7622: fix potential uninitialized value being returned commit d6ed93551320 ("pinctrl: mediatek: add pinctrl driver for MT7622 SoC") leads to the following static checker warning: drivers/pinctrl/mediatek/pinctrl-mt7622.c:1419 mtk_gpio_get() error: uninitialized symbol 'value'. 1412 static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) 1413 { 1414 struct mtk_pinctrl *hw = dev_get_drvdata(chip->parent); 1415 int value; 1416 1417 mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value); ^^^^^^^^^^^^^^^^ 1418 1419 return !!value; 1420 } The appropriate error handling must be added to avoid the potential error caused by uninitialized value being returned. Reported-by: Dan Carpenter Signed-off-by: Sean Wang Reviewed-by: Matthias Brugger Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-mt7622.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c index 3824d82888ac..dc32e3c3bd73 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c @@ -1412,9 +1412,11 @@ static struct pinctrl_desc mtk_desc = { static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) { struct mtk_pinctrl *hw = dev_get_drvdata(chip->parent); - int value; + int value, err; - mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value); + err = mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value); + if (err) + return err; return !!value; } -- cgit From 8b3d9cd48d15f34328ec69ecff5ca860e7068e36 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 10 Jan 2018 00:28:25 +0800 Subject: pinctrl: mediatek: mt7622: align error handling of mtk_hw_get_value call Make consistent error handling of all mtk_hw_get_value occurrences using propagating error code from the internal instead of creating a new one. Signed-off-by: Sean Wang Reviewed-by: Matthias Brugger Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-mt7622.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c index dc32e3c3bd73..06e8406c4440 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c @@ -1160,7 +1160,7 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_OUTPUT_ENABLE: err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val); if (err) - return -EINVAL; + return err; /* HW takes input mode as zero; output mode as non-zero */ if ((val && param == PIN_CONFIG_INPUT_ENABLE) || @@ -1184,11 +1184,11 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_DRIVE_STRENGTH: err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E4, &val); if (err) - return -EINVAL; + return err; err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E8, &val2); if (err) - return -EINVAL; + return err; /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1) * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1) @@ -1203,7 +1203,7 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, err = mtk_hw_get_value(hw, pin, reg, &val); if (err) - return -EINVAL; + return err; ret = val; -- cgit From cd8c0bb2bd57c48c451ebea86065257ef2500b00 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 13 Dec 2017 21:55:50 +0800 Subject: rtc: r7301: Fix a possible sleep-in-atomic bug in rtc7301_read_time The driver may sleep under a spinlock. The function call path is: rtc7301_read_time (acquire the spinlock) rtc7301_wait_while_busy usleep_range --> may sleep To fix it, usleep_range is replaced with udelay. This bug is found by my static analysis tool(DSAC) and checked by my code review. Signed-off-by: Jia-Ju Bai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-r7301.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c index 28d540885f3d..d846e9703ad6 100644 --- a/drivers/rtc/rtc-r7301.c +++ b/drivers/rtc/rtc-r7301.c @@ -95,7 +95,7 @@ static int rtc7301_wait_while_busy(struct rtc7301_priv *priv) if (!(val & RTC7301_CONTROL_BUSY)) return 0; - usleep_range(200, 300); + udelay(300); } return -ETIMEDOUT; -- cgit From 298c8545206b2dd963079ff48fafd909e099856e Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 13 Dec 2017 21:56:04 +0800 Subject: rtc: r7301: Fix a possible sleep-in-atomic bug in rtc7301_set_time The driver may sleep under a spinlock. The function call path is: rtc7301_set_time (acquire the spinlock) usleep_range --> may sleep To fix it, usleep_range is replaced with udelay. This bug is found by my static analysis tool(DSAC) and checked by my code review. Signed-off-by: Jia-Ju Bai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-r7301.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c index d846e9703ad6..500e8c8a2605 100644 --- a/drivers/rtc/rtc-r7301.c +++ b/drivers/rtc/rtc-r7301.c @@ -235,7 +235,7 @@ static int rtc7301_set_time(struct device *dev, struct rtc_time *tm) spin_lock_irqsave(&priv->lock, flags); rtc7301_stop(priv); - usleep_range(200, 300); + udelay(300); rtc7301_select_bank(priv, 0); rtc7301_write_time(priv, tm, false); rtc7301_start(priv); -- cgit From 83c880f79e88cc60593f627e612326f5d43db81e Mon Sep 17 00:00:00 2001 From: Patrick Bruenn Date: Mon, 18 Dec 2017 12:51:32 +0100 Subject: rtc: add mxc driver for i.MX53 SRTC Neither rtc-imxdi, rtc-mxc nor rtc-snvs are compatible with i.MX53. This is driver enables support for the low power domain SRTC features: - 32-bit MSB of non-rollover time counter - 32-bit alarm register Select the new config option RTC_DRV_MXC_V2 to build this driver Based on: http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01 Signed-off-by: Patrick Bruenn Acked-by: Philippe Ombredanne Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-mxc_v2.c | 422 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 drivers/rtc/rtc-mxc_v2.c (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 64f4b164932a..b71cc7b5fbc9 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1699,6 +1699,16 @@ config RTC_DRV_MXC This driver can also be built as a module, if so, the module will be called "rtc-mxc". +config RTC_DRV_MXC_V2 + tristate "Freescale MXC Real Time Clock for i.MX53" + depends on ARCH_MXC + help + If you say yes here you get support for the Freescale MXC + SRTC module in i.MX53 processor. + + This driver can also be built as a module, if so, the module + will be called "rtc-mxc_v2". + config RTC_DRV_SNVS tristate "Freescale SNVS RTC support" select REGMAP_MMIO diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index cf9d29e34dbd..6dfbbe9cd8a2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o +obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c new file mode 100644 index 000000000000..b637095b0716 --- /dev/null +++ b/drivers/rtc/rtc-mxc_v2.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Real Time Clock (RTC) Driver for i.MX53 + * Copyright (c) 2004-2011 Freescale Semiconductor, Inc. + * Copyright (c) 2017 Beckhoff Automation GmbH & Co. KG + */ + +#include +#include +#include +#include +#include + +#define SRTC_LPPDR_INIT 0x41736166 /* init for glitch detect */ + +#define SRTC_LPCR_EN_LP BIT(3) /* lp enable */ +#define SRTC_LPCR_WAE BIT(4) /* lp wakeup alarm enable */ +#define SRTC_LPCR_ALP BIT(7) /* lp alarm flag */ +#define SRTC_LPCR_NSA BIT(11) /* lp non secure access */ +#define SRTC_LPCR_NVE BIT(14) /* lp non valid state exit bit */ +#define SRTC_LPCR_IE BIT(15) /* lp init state exit bit */ + +#define SRTC_LPSR_ALP BIT(3) /* lp alarm flag */ +#define SRTC_LPSR_NVES BIT(14) /* lp non-valid state exit status */ +#define SRTC_LPSR_IES BIT(15) /* lp init state exit status */ + +#define SRTC_LPSCMR 0x00 /* LP Secure Counter MSB Reg */ +#define SRTC_LPSCLR 0x04 /* LP Secure Counter LSB Reg */ +#define SRTC_LPSAR 0x08 /* LP Secure Alarm Reg */ +#define SRTC_LPCR 0x10 /* LP Control Reg */ +#define SRTC_LPSR 0x14 /* LP Status Reg */ +#define SRTC_LPPDR 0x18 /* LP Power Supply Glitch Detector Reg */ + +/* max. number of retries to read registers, 120 was max during test */ +#define REG_READ_TIMEOUT 2000 + +struct mxc_rtc_data { + struct rtc_device *rtc; + void __iomem *ioaddr; + struct clk *clk; + spinlock_t lock; /* protects register access */ + int irq; +}; + +/* + * This function does write synchronization for writes to the lp srtc block. + * To take care of the asynchronous CKIL clock, all writes from the IP domain + * will be synchronized to the CKIL domain. + * The caller should hold the pdata->lock + */ +static void mxc_rtc_sync_lp_locked(struct device *dev, void __iomem *ioaddr) +{ + unsigned int i; + + /* Wait for 3 CKIL cycles */ + for (i = 0; i < 3; i++) { + const u32 count = readl(ioaddr + SRTC_LPSCLR); + unsigned int timeout = REG_READ_TIMEOUT; + + while ((readl(ioaddr + SRTC_LPSCLR)) == count) { + if (!--timeout) { + dev_err_once(dev, "SRTC_LPSCLR stuck! Check your hw.\n"); + return; + } + } + } +} + +/* This function is the RTC interrupt service routine. */ +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id) +{ + struct device *dev = dev_id; + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + void __iomem *ioaddr = pdata->ioaddr; + unsigned long flags; + u32 lp_status; + u32 lp_cr; + + spin_lock_irqsave(&pdata->lock, flags); + if (clk_enable(pdata->clk)) { + spin_unlock_irqrestore(&pdata->lock, flags); + return IRQ_NONE; + } + + lp_status = readl(ioaddr + SRTC_LPSR); + lp_cr = readl(ioaddr + SRTC_LPCR); + + /* update irq data & counter */ + if (lp_status & SRTC_LPSR_ALP) { + if (lp_cr & SRTC_LPCR_ALP) + rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF); + + /* disable further lp alarm interrupts */ + lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE); + } + + /* Update interrupt enables */ + writel(lp_cr, ioaddr + SRTC_LPCR); + + /* clear interrupt status */ + writel(lp_status, ioaddr + SRTC_LPSR); + + mxc_rtc_sync_lp_locked(dev, ioaddr); + clk_disable(pdata->clk); + spin_unlock_irqrestore(&pdata->lock, flags); + return IRQ_HANDLED; +} + +/* + * Enable clk and aquire spinlock + * @return 0 if successful; non-zero otherwise. + */ +static int mxc_rtc_lock(struct mxc_rtc_data *const pdata) +{ + int ret; + + spin_lock_irq(&pdata->lock); + ret = clk_enable(pdata->clk); + if (ret) { + spin_unlock_irq(&pdata->lock); + return ret; + } + return 0; +} + +static int mxc_rtc_unlock(struct mxc_rtc_data *const pdata) +{ + clk_disable(pdata->clk); + spin_unlock_irq(&pdata->lock); + return 0; +} + +/* + * This function reads the current RTC time into tm in Gregorian date. + * + * @param tm contains the RTC time value upon return + * + * @return 0 if successful; non-zero otherwise. + */ +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + const int clk_failed = clk_enable(pdata->clk); + + if (!clk_failed) { + const time64_t now = readl(pdata->ioaddr + SRTC_LPSCMR); + + rtc_time64_to_tm(now, tm); + clk_disable(pdata->clk); + return 0; + } + return clk_failed; +} + +/* + * This function sets the internal RTC time based on tm in Gregorian date. + * + * @param tm the time value to be set in the RTC + * + * @return 0 if successful; non-zero otherwise. + */ +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + time64_t time = rtc_tm_to_time64(tm); + int ret; + + if (time > U32_MAX) { + dev_err(dev, "RTC exceeded by %llus\n", time - U32_MAX); + return -EINVAL; + } + + ret = mxc_rtc_lock(pdata); + if (ret) + return ret; + + writel(time, pdata->ioaddr + SRTC_LPSCMR); + mxc_rtc_sync_lp_locked(dev, pdata->ioaddr); + return mxc_rtc_unlock(pdata); +} + +/* + * This function reads the current alarm value into the passed in \b alrm + * argument. It updates the \b alrm's pending field value based on the whether + * an alarm interrupt occurs or not. + * + * @param alrm contains the RTC alarm value upon return + * + * @return 0 if successful; non-zero otherwise. + */ +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + void __iomem *ioaddr = pdata->ioaddr; + int ret; + + ret = mxc_rtc_lock(pdata); + if (ret) + return ret; + + rtc_time_to_tm(readl(ioaddr + SRTC_LPSAR), &alrm->time); + alrm->pending = !!(readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP); + return mxc_rtc_unlock(pdata); +} + +/* + * Enable/Disable alarm interrupt + * The caller should hold the pdata->lock + */ +static void mxc_rtc_alarm_irq_enable_locked(struct mxc_rtc_data *pdata, + unsigned int enable) +{ + u32 lp_cr = readl(pdata->ioaddr + SRTC_LPCR); + + if (enable) + lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE); + else + lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE); + + writel(lp_cr, pdata->ioaddr + SRTC_LPCR); +} + +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + int ret = mxc_rtc_lock(pdata); + + if (ret) + return ret; + + mxc_rtc_alarm_irq_enable_locked(pdata, enable); + return mxc_rtc_unlock(pdata); +} + +/* + * This function sets the RTC alarm based on passed in alrm. + * + * @param alrm the alarm value to be set in the RTC + * + * @return 0 if successful; non-zero otherwise. + */ +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + const time64_t time = rtc_tm_to_time64(&alrm->time); + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + int ret = mxc_rtc_lock(pdata); + + if (ret) + return ret; + + if (time > U32_MAX) { + dev_err(dev, "Hopefully I am out of service by then :-(\n"); + return -EINVAL; + } + + writel((u32)time, pdata->ioaddr + SRTC_LPSAR); + + /* clear alarm interrupt status bit */ + writel(SRTC_LPSR_ALP, pdata->ioaddr + SRTC_LPSR); + mxc_rtc_sync_lp_locked(dev, pdata->ioaddr); + + mxc_rtc_alarm_irq_enable_locked(pdata, alrm->enabled); + mxc_rtc_sync_lp_locked(dev, pdata->ioaddr); + mxc_rtc_unlock(pdata); + return ret; +} + +static const struct rtc_class_ops mxc_rtc_ops = { + .read_time = mxc_rtc_read_time, + .set_time = mxc_rtc_set_time, + .read_alarm = mxc_rtc_read_alarm, + .set_alarm = mxc_rtc_set_alarm, + .alarm_irq_enable = mxc_rtc_alarm_irq_enable, +}; + +static int mxc_rtc_wait_for_flag(void *__iomem ioaddr, int flag) +{ + unsigned int timeout = REG_READ_TIMEOUT; + + while (!(readl(ioaddr) & flag)) { + if (!--timeout) + return -EBUSY; + } + return 0; +} + +static int mxc_rtc_probe(struct platform_device *pdev) +{ + struct mxc_rtc_data *pdata; + struct resource *res; + void __iomem *ioaddr; + int ret = 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->ioaddr)) + return PTR_ERR(pdata->ioaddr); + + ioaddr = pdata->ioaddr; + + pdata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pdata->clk)) { + dev_err(&pdev->dev, "unable to get rtc clock!\n"); + return PTR_ERR(pdata->clk); + } + + spin_lock_init(&pdata->lock); + pdata->irq = platform_get_irq(pdev, 0); + if (pdata->irq < 0) + return pdata->irq; + + device_init_wakeup(&pdev->dev, 1); + + ret = clk_prepare_enable(pdata->clk); + if (ret) + return ret; + /* initialize glitch detect */ + writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR); + + /* clear lp interrupt status */ + writel(0xFFFFFFFF, ioaddr + SRTC_LPSR); + + /* move out of init state */ + writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR); + ret = mxc_rtc_wait_for_flag(ioaddr + SRTC_LPSR, SRTC_LPSR_IES); + if (ret) { + dev_err(&pdev->dev, "Timeout waiting for SRTC_LPSR_IES\n"); + clk_disable_unprepare(pdata->clk); + return ret; + } + + /* move out of non-valid state */ + writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA | + SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR); + ret = mxc_rtc_wait_for_flag(ioaddr + SRTC_LPSR, SRTC_LPSR_NVES); + if (ret) { + dev_err(&pdev->dev, "Timeout waiting for SRTC_LPSR_NVES\n"); + clk_disable_unprepare(pdata->clk); + return ret; + } + + clk_disable(pdata->clk); + platform_set_drvdata(pdev, pdata); + ret = + devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt, 0, + pdev->name, &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "interrupt not available.\n"); + clk_unprepare(pdata->clk); + return ret; + } + + pdata->rtc = + devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops, + THIS_MODULE); + if (IS_ERR(pdata->rtc)) { + clk_unprepare(pdata->clk); + return PTR_ERR(pdata->rtc); + } + + return 0; +} + +static int __exit mxc_rtc_remove(struct platform_device *pdev) +{ + struct mxc_rtc_data *pdata = platform_get_drvdata(pdev); + + clk_disable_unprepare(pdata->clk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mxc_rtc_suspend(struct device *dev) +{ + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(pdata->irq); + + return 0; +} + +static int mxc_rtc_resume(struct device *dev) +{ + struct mxc_rtc_data *pdata = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(pdata->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(mxc_rtc_pm_ops, mxc_rtc_suspend, mxc_rtc_resume); + +static const struct of_device_id mxc_ids[] = { + { .compatible = "fsl,imx53-rtc", }, + {} +}; + +static struct platform_driver mxc_rtc_driver = { + .driver = { + .name = "mxc_rtc_v2", + .of_match_table = mxc_ids, + .pm = &mxc_rtc_pm_ops, + }, + .probe = mxc_rtc_probe, + .remove = mxc_rtc_remove, +}; + +module_platform_driver(mxc_rtc_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("Real Time Clock (RTC) Driver for i.MX53"); +MODULE_LICENSE("GPL"); -- cgit From a9c705a8bd52d8a5205cc779d6e64af4321a9fa8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 21 Dec 2017 09:43:24 -0200 Subject: rtc: mxc_v2: Remove unnecessary platform_get_resource() error check devm_ioremap_resource() already checks if the resource is NULL, so remove the unnecessary platform_get_resource() error check. Signed-off-by: Fabio Estevam Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mxc_v2.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index b637095b0716..eecc0cf9ee95 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -296,9 +296,6 @@ static int mxc_rtc_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pdata->ioaddr)) return PTR_ERR(pdata->ioaddr); -- cgit From db00d38e7b59ae913cfa10f1c40bf656a969fb82 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 2 Jan 2018 10:43:33 +0100 Subject: rtc: mxc_v2: remove __exit annotation The mxc_rtc_remove is incorrectly annotated as __exit: `mxc_rtc_remove' referenced in section `.data' of drivers/rtc/rtc-mxc_v2.o: defined in discarded section `.exit.text' of drivers/rtc/rtc-mxc_v2.o This should not be done, as devices can be dynamically bound and unbound to a driver. Fixes: 54c47014b474 ("rtc: add mxc driver for i.MX53 SRTC") Signed-off-by: Arnd Bergmann Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mxc_v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index eecc0cf9ee95..784221dfc9c7 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -365,7 +365,7 @@ static int mxc_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit mxc_rtc_remove(struct platform_device *pdev) +static int mxc_rtc_remove(struct platform_device *pdev) { struct mxc_rtc_data *pdata = platform_get_drvdata(pdev); -- cgit From 4adf7bf7bbaefe71133305193c25d32863115dda Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Wed, 2 Nov 2016 21:09:44 +0100 Subject: firewire: net: max MTU off by one The latest max_mtu patch missed that datagram_size is actually one less than the datagram's Total Length. Fixes: 357f4aae859b ("firewire: net: really fix maximum possible MTU") Signed-off-by: Stefan Richter --- drivers/firewire/net.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 242359c2d1f1..60e75e6d9104 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1480,9 +1480,14 @@ static int fwnet_probe(struct fw_unit *unit, goto out; dev->local_fifo = dev->handler.offset; + /* + * default MTU: RFC 2734 cl. 4, RFC 3146 cl. 4 + * maximum MTU: RFC 2734 cl. 4.2, fragment encapsulation header's + * maximum possible datagram_size + 1 = 0xfff + 1 + */ net->mtu = 1500U; net->min_mtu = ETH_MIN_MTU; - net->max_mtu = 0xfff; + net->max_mtu = 4096U; /* Set our hardware address while we're at it */ ha = (union fwnet_hwaddr *)net->dev_addr; -- cgit From 188775181bc05f29372b305ef96485840e351fde Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 3 Nov 2017 20:28:57 +0900 Subject: firewire-ohci: work around oversized DMA reads on JMicron controllers At least some JMicron controllers issue buggy oversized DMA reads when fetching context descriptors, always fetching 0x20 bytes at once for descriptors which are only 0x10 bytes long. This is often harmless, but can cause page faults on modern systems with IOMMUs: DMAR: [DMA Read] Request device [05:00.0] fault addr fff56000 [fault reason 06] PTE Read access is not set firewire_ohci 0000:05:00.0: DMA context IT0 has stopped, error code: evt_descriptor_read This works around the problem by always leaving 0x10 padding bytes at the end of descriptor buffer pages, which should be harmless to do unconditionally for controllers in case others have the same behavior. Signed-off-by: Hector Martin Reviewed-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 8bf89267dc25..d731b413cb2c 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1130,7 +1130,13 @@ static int context_add_buffer(struct context *ctx) return -ENOMEM; offset = (void *)&desc->buffer - (void *)desc; - desc->buffer_size = PAGE_SIZE - offset; + /* + * Some controllers, like JMicron ones, always issue 0x20-byte DMA reads + * for descriptors, even 0x10-byte ones. This can cause page faults when + * an IOMMU is in use and the oversized read crosses a page boundary. + * Work around this by always leaving at least 0x10 bytes of padding. + */ + desc->buffer_size = PAGE_SIZE - offset - 0x10; desc->buffer_bus = bus_addr + offset; desc->used = 0; -- cgit From 9e422131167583092a560c1ac4837a12aa11da96 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 Dec 2017 22:57:56 +0100 Subject: i2c: sh_mobile: move type detection upwards For refactoring reasons, we will need this information before the setup callback. Also, simplify the comment to a oneliner. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index b01607b4fce2..1ac896e46b39 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -873,6 +873,10 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->bus_speed = ret ? STANDARD_MODE : bus_speed; pd->clks_per_count = 1; + /* Newer variants come with two new bits in ICIC */ + if (resource_size(res) > 0x17) + pd->flags |= IIC_FLAG_HAS_ICIC67; + config = of_device_get_match_data(&dev->dev); if (config) { pd->clks_per_count = config->clks_per_count; @@ -881,12 +885,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) config->setup(pd); } - /* The IIC blocks on SH-Mobile ARM processors - * come with two new bits in ICIC. - */ - if (resource_size(res) > 0x17) - pd->flags |= IIC_FLAG_HAS_ICIC67; - ret = sh_mobile_i2c_init(pd); if (ret) return ret; -- cgit From 12742b6ac1215496a60fcf33d1d8397af7512840 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 Dec 2017 22:57:57 +0100 Subject: i2c: sh_mobile: allow setup callback to return errno The setup callback will be more generic and, thus, need to be able to return error codes. Change the return type to 'int' for that. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 1ac896e46b39..a3a377a10fa7 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -149,7 +149,7 @@ struct sh_mobile_i2c_data { struct sh_mobile_dt_config { int clks_per_count; - void (*setup)(struct sh_mobile_i2c_data *pd); + int (*setup)(struct sh_mobile_i2c_data *pd); }; #define IIC_FLAG_HAS_ICIC67 (1 << 0) @@ -749,7 +749,7 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = { * r8a7740 chip has lasting errata on I2C I/O pad reset. * this is work-around for it. */ -static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) +static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) { iic_set_clr(pd, ICCR, ICCR_ICE, 0); iic_rd(pd, ICCR); /* dummy read */ @@ -770,6 +770,8 @@ static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) udelay(10); iic_wr(pd, ICCR, ICCR_TRS); udelay(10); + + return 0; } static const struct sh_mobile_dt_config default_dt_config = { @@ -881,8 +883,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (config) { pd->clks_per_count = config->clks_per_count; - if (config->setup) - config->setup(pd); + if (config->setup) { + ret = config->setup(pd); + if (ret) + return ret; + } } ret = sh_mobile_i2c_init(pd); -- cgit From b3750b6278b2f37618931352df8de6e7ddbecd1e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 Dec 2017 22:57:58 +0100 Subject: i2c: sh_mobile: require setup callback Require the setup callback and move the frequency calculation into it. This is in preparation for supporting multiple formulas. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index a3a377a10fa7..88af45225003 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -771,15 +771,17 @@ static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) iic_wr(pd, ICCR, ICCR_TRS); udelay(10); - return 0; + return sh_mobile_i2c_init(pd); } static const struct sh_mobile_dt_config default_dt_config = { .clks_per_count = 1, + .setup = sh_mobile_i2c_init, }; static const struct sh_mobile_dt_config fast_clock_dt_config = { .clks_per_count = 2, + .setup = sh_mobile_i2c_init, }; static const struct sh_mobile_dt_config r8a7740_dt_config = { @@ -882,15 +884,10 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) config = of_device_get_match_data(&dev->dev); if (config) { pd->clks_per_count = config->clks_per_count; - - if (config->setup) { - ret = config->setup(pd); - if (ret) - return ret; - } + ret = config->setup(pd); + } else { + ret = sh_mobile_i2c_init(pd); } - - ret = sh_mobile_i2c_init(pd); if (ret) return ret; -- cgit From 023c22fd82ce0c62d7490ace6388191375ef4133 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 Dec 2017 22:57:59 +0100 Subject: i2c: sh_mobile: let RuntimePM do the clock handling Start RuntimePM a bit earlier, so we can use it to enable the clock during probe for frequency calculations. Make sure it is enabled before calling setup(). Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 88af45225003..f1a9b971e2c1 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -252,11 +252,7 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) u32 tHIGH, tLOW, tf; uint16_t max_val; - /* Get clock rate after clock is enabled */ - clk_prepare_enable(pd->clk); - i2c_clk_khz = clk_get_rate(pd->clk) / 1000; - clk_disable_unprepare(pd->clk); - i2c_clk_khz /= pd->clks_per_count; + i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count; if (pd->bus_speed == STANDARD_MODE) { tLOW = 47; /* tLOW = 4.7 us */ @@ -881,6 +877,20 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (resource_size(res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; + /* Enable Runtime PM for this device. + * + * Also tell the Runtime PM core to ignore children + * for this device since it is valid for us to suspend + * this I2C master driver even though the slave devices + * on the I2C bus may not be suspended. + * + * The state of the I2C hardware bus is unaffected by + * the Runtime PM state. + */ + pm_suspend_ignore_children(&dev->dev, true); + pm_runtime_enable(&dev->dev); + pm_runtime_get_sync(&dev->dev); + config = of_device_get_match_data(&dev->dev); if (config) { pd->clks_per_count = config->clks_per_count; @@ -888,6 +898,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) } else { ret = sh_mobile_i2c_init(pd); } + + pm_runtime_put_sync(&dev->dev); if (ret) return ret; @@ -896,19 +908,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->dma_direction = DMA_NONE; pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER); - /* Enable Runtime PM for this device. - * - * Also tell the Runtime PM core to ignore children - * for this device since it is valid for us to suspend - * this I2C master driver even though the slave devices - * on the I2C bus may not be suspended. - * - * The state of the I2C hardware bus is unaffected by - * the Runtime PM state. - */ - pm_suspend_ignore_children(&dev->dev, true); - pm_runtime_enable(&dev->dev); - /* setup the private data */ adap = &pd->adap; i2c_set_adapdata(adap, pd); -- cgit From c3449f73a80b2b04a3f7ff69be871c153ea1a9fa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 Dec 2017 22:58:00 +0100 Subject: i2c: sh_mobile: add helper to check frequency calculations Because we will add a second formula soon, put the sanity checks for the computed results into a separate function. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 49 +++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index f1a9b971e2c1..b111191a449a 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -246,11 +246,36 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf) return (((count_khz * (tHIGH + tf)) + 5000) / 10000); } +static int sh_mobile_i2c_check_timing(struct sh_mobile_i2c_data *pd) +{ + u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff; + + if (pd->iccl > max_val || pd->icch > max_val) { + dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n", + pd->iccl, pd->icch); + return -EINVAL; + } + + /* one more bit of ICCL in ICIC */ + if (pd->iccl & 0x100) + pd->icic |= ICIC_ICCLB8; + else + pd->icic &= ~ICIC_ICCLB8; + + /* one more bit of ICCH in ICIC */ + if (pd->icch & 0x100) + pd->icic |= ICIC_ICCHB8; + else + pd->icic &= ~ICIC_ICCHB8; + + dev_dbg(pd->dev, "timing values: L/H=0x%x/0x%x\n", pd->iccl, pd->icch); + return 0; +} + static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk_khz; u32 tHIGH, tLOW, tf; - uint16_t max_val; i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count; @@ -271,27 +296,7 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); - max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff; - if (pd->iccl > max_val || pd->icch > max_val) { - dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n", - pd->iccl, pd->icch); - return -EINVAL; - } - - /* one more bit of ICCL in ICIC */ - if (pd->iccl & 0x100) - pd->icic |= ICIC_ICCLB8; - else - pd->icic &= ~ICIC_ICCLB8; - - /* one more bit of ICCH in ICIC */ - if (pd->icch & 0x100) - pd->icic |= ICIC_ICCHB8; - else - pd->icic &= ~ICIC_ICCHB8; - - dev_dbg(pd->dev, "timing values: L/H=0x%x/0x%x\n", pd->iccl, pd->icch); - return 0; + return sh_mobile_i2c_check_timing(pd); } static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, -- cgit From 4ecfb9d3b229fff538c706650a8208fa03660c22 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 Dec 2017 22:58:01 +0100 Subject: i2c: sh_mobile: add new frequency calculation for later SoC The formula to generate the desired bus speeds has changed a little over time. Implement the new formula and allow drivers to opt-in by changing to this new config set. Ensure in probe that we don't divide by zero. The returned values on a R-Car H2 (r8a7790/Lager board) match the suggested values in the datasheet. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index b111191a449a..a0fddfe3c449 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -299,6 +299,18 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) return sh_mobile_i2c_check_timing(pd); } +static int sh_mobile_i2c_v2_init(struct sh_mobile_i2c_data *pd) +{ + unsigned long clks_per_cycle; + + /* L = 5, H = 4, L + H = 9 */ + clks_per_cycle = clk_get_rate(pd->clk) / pd->bus_speed; + pd->iccl = DIV_ROUND_UP(clks_per_cycle * 5 / 9 - 1, pd->clks_per_count); + pd->icch = DIV_ROUND_UP(clks_per_cycle * 4 / 9 - 5, pd->clks_per_count); + + return sh_mobile_i2c_check_timing(pd); +} + static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op op, unsigned char data) { @@ -785,6 +797,11 @@ static const struct sh_mobile_dt_config fast_clock_dt_config = { .setup = sh_mobile_i2c_init, }; +static const struct sh_mobile_dt_config v2_freq_calc_dt_config = { + .clks_per_count = 2, + .setup = sh_mobile_i2c_v2_init, +}; + static const struct sh_mobile_dt_config r8a7740_dt_config = { .clks_per_count = 1, .setup = sh_mobile_i2c_r8a7740_workaround, @@ -875,7 +892,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return PTR_ERR(pd->reg); ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed); - pd->bus_speed = ret ? STANDARD_MODE : bus_speed; + pd->bus_speed = (ret || !bus_speed) ? STANDARD_MODE : bus_speed; pd->clks_per_count = 1; /* Newer variants come with two new bits in ICIC */ -- cgit From 6e318d9e3768b91707d8325068eeef88999aa8ae Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 Dec 2017 22:58:02 +0100 Subject: i2c: sh_mobile: let r8a7790 (R-Car H2) use the new formula Make use of the new formula for more precise bus frequencies. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index a0fddfe3c449..d856bc211715 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -810,7 +810,7 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = { static const struct of_device_id sh_mobile_i2c_dt_ids[] = { { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config }, - { .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config }, { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config }, -- cgit From aad550f93fbc28d562a624700f9c12c9b9055a5e Mon Sep 17 00:00:00 2001 From: Radu Rendec Date: Fri, 18 Aug 2017 17:01:28 +0100 Subject: i2c: ismt: dump registers at the end of transactions This patch dumps general and master registers at the end of transactions when debugging is enabled. Previously, registers were only dumped before submitting new descriptors (at the beginning of transactions). This helps debugging if some registers change as result of a failed transaction (e.g. bits are set in the ERRSTS general register). Signed-off-by: Radu Rendec Acked-by: Neil Horman Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ismt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index c0d0f34d34f3..45ad9b847c58 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -324,6 +324,8 @@ static int ismt_process_desc(const struct ismt_desc *desc, dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); __ismt_desc_dump(&priv->pci_dev->dev, desc); + ismt_gen_reg_dump(priv); + ismt_mstr_reg_dump(priv); if (desc->status & ISMT_DESC_SCS) { if (read_write == I2C_SMBUS_WRITE && -- cgit From 6d106139191e58b9f4ef126cfc1e3c26c0d6702e Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Thu, 7 Dec 2017 17:20:00 +0700 Subject: i2c: mpc: get MPC8xxx I2C clock prescaler before using it in calculations Obtaining the actual I2C clock prescaler value in mpc_i2c_setup_8xxx() only happens when the clock parameter is set to something other than MPC_I2C_CLOCK_LEGACY. When the clock parameter is exactly MPC_I2C_CLOCK_LEGACY, the prescaler parameter is used in arithmetic division as provided by the caller, resulting in a division by zero for the majority of processors supported by the module. Avoid division by zero by obtaining the actual I2C clock prescaler in mpc_i2c_setup_8xxx() unconditionally regardless of the passed clock value. Signed-off-by: Arseny Solokha Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 950a9d74f54d..6ad87555f71e 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -382,18 +382,18 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 divider; int i; - if (clock == MPC_I2C_CLOCK_LEGACY) { - /* see below - default fdr = 0x1031 -> div = 16 * 3072 */ - *real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072); - return -EINVAL; - } - /* Determine proper divider value */ if (of_device_is_compatible(node, "fsl,mpc8544-i2c")) prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2; if (!prescaler) prescaler = mpc_i2c_get_prescaler_8xxx(); + if (clock == MPC_I2C_CLOCK_LEGACY) { + /* see below - default fdr = 0x1031 -> div = 16 * 3072 */ + *real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072); + return -EINVAL; + } + divider = fsl_get_sys_freq() / clock / prescaler; pr_debug("I2C: src_clock=%d clock=%d divider=%d\n", -- cgit From f6214f6f2b11e696a83b97f90b7a0f04efb8ec09 Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Thu, 7 Dec 2017 17:20:01 +0700 Subject: i2c: mpc: unify obtaining the MPC8533/44 I2C clock prescaler w/ MPC8xxx Commit 8ce795cb0c6b ("i2c: mpc: assign the correct prescaler from SVR") introduced the common helper function for obtaining the actual clock prescaler value for MPC85xx. However, getting the prescaler for MPC8544 which depends on the SEC frequency ratio on this platform, has been always performed separately based on the corresponding Device Tree configuration. Move special handling of MPC8544 into that common helper. Make it dependent on the SoC version and not on Device Tree compatible node, as is the case with all other SoCs. Handle MPC8533 the same way which is similar to MPC8544 in this regard, according to AN2919 "Determining the I2C Frequency Divider Ratio for SCL". Signed-off-by: Arseny Solokha Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 6ad87555f71e..648a5afded64 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -350,7 +350,11 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) static u32 mpc_i2c_get_prescaler_8xxx(void) { - /* mpc83xx and mpc82xx all have prescaler 1 */ + /* + * According to the AN2919 all MPC824x have prescaler 1, while MPC83xx + * may have prescaler 1, 2, or 3, depending on the power-on + * configuration. + */ u32 prescaler = 1; /* mpc85xx */ @@ -367,6 +371,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void) || (SVR_SOC_VER(svr) == SVR_8610)) /* the above 85xx SoCs have prescaler 1 */ prescaler = 1; + else if ((SVR_SOC_VER(svr) == SVR_8533) + || (SVR_SOC_VER(svr) == SVR_8544)) + /* the above 85xx SoCs have prescaler 3 or 2 */ + prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2; else /* all the other 85xx have prescaler 2 */ prescaler = 2; @@ -383,8 +391,6 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, int i; /* Determine proper divider value */ - if (of_device_is_compatible(node, "fsl,mpc8544-i2c")) - prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2; if (!prescaler) prescaler = mpc_i2c_get_prescaler_8xxx(); -- cgit From 7575a745f9ea12d7fdbc7cf02c862bad0a47c50f Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Thu, 7 Dec 2017 17:20:02 +0700 Subject: i2c: mpc: fix PORDEVSR2 mask for MPC8533/44 According to the reference manuals for the corresponding SoCs, SEC frequency ratio configuration is indicated by bit 26 of the POR Device Status Register 2. Consequently, SEC_CFG bit should be tested by mask 0x20, not 0x80. Testing the wrong bit leads to selection of wrong I2C clock prescaler on those SoCs. Signed-off-by: Arseny Solokha Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 648a5afded64..aac0ec6dc5fc 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -332,14 +332,18 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) if (prop) { /* * Map and check POR Device Status Register 2 - * (PORDEVSR2) at 0xE0014 + * (PORDEVSR2) at 0xE0014. Note than while MPC8533 + * and MPC8544 indicate SEC frequency ratio + * configuration as bit 26 in PORDEVSR2, other MPC8xxx + * parts may store it differently or may not have it + * at all. */ reg = ioremap(get_immrbase() + *prop + 0x14, 0x4); if (!reg) printk(KERN_ERR "Error: couldn't map PORDEVSR2\n"); else - val = in_be32(reg) & 0x00000080; /* sec-cfg */ + val = in_be32(reg) & 0x00000020; /* sec-cfg */ iounmap(reg); } } -- cgit From 38a99bd7730efdd0ca6ce2531a2761778fca3293 Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Wed, 10 Jan 2018 18:36:07 +0700 Subject: i2c: mpc: always determine I2C clock prescaler at runtime Remove the facility for setting the prescaler value at compile time entirely. It was only used for two SoCs, duplicating the actual value for one of them and setting sometimes bogus value for another. Make all MPC8xxx SoCs obtain their actual I2C clock prescaler from a single place in the code. Changes from v2: - left Device Tree compatibles in place Signed-off-by: Arseny Solokha Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index aac0ec6dc5fc..d94f05c8b8b7 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -78,9 +78,7 @@ struct mpc_i2c_divider { }; struct mpc_i2c_data { - void (*setup)(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler); - u32 prescaler; + void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock); }; static inline void writeccr(struct mpc_i2c *i2c, u32 x) @@ -201,7 +199,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = { }; static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, - int prescaler, u32 *real_clk) + u32 *real_clk) { const struct mpc_i2c_divider *div = NULL; unsigned int pvr = mfspr(SPRN_PVR); @@ -236,7 +234,7 @@ static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, static void mpc_i2c_setup_52xx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { int ret, fdr; @@ -246,7 +244,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, return; } - ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk); + ret = mpc_i2c_get_fdr_52xx(node, clock, &i2c->real_clk); fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); @@ -258,7 +256,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, #else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */ static void mpc_i2c_setup_52xx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { } #endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */ @@ -266,7 +264,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, #ifdef CONFIG_PPC_MPC512x static void mpc_i2c_setup_512x(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { struct device_node *node_ctrl; void __iomem *ctrl; @@ -289,12 +287,12 @@ static void mpc_i2c_setup_512x(struct device_node *node, } /* The clock setup for the 52xx works also fine for the 512x */ - mpc_i2c_setup_52xx(node, i2c, clock, prescaler); + mpc_i2c_setup_52xx(node, i2c, clock); } #else /* CONFIG_PPC_MPC512x */ static void mpc_i2c_setup_512x(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { } #endif /* CONFIG_PPC_MPC512x */ @@ -388,16 +386,13 @@ static u32 mpc_i2c_get_prescaler_8xxx(void) } static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, - u32 prescaler, u32 *real_clk) + u32 *real_clk) { const struct mpc_i2c_divider *div = NULL; + u32 prescaler = mpc_i2c_get_prescaler_8xxx(); u32 divider; int i; - /* Determine proper divider value */ - if (!prescaler) - prescaler = mpc_i2c_get_prescaler_8xxx(); - if (clock == MPC_I2C_CLOCK_LEGACY) { /* see below - default fdr = 0x1031 -> div = 16 * 3072 */ *real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072); @@ -425,7 +420,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, static void mpc_i2c_setup_8xxx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { int ret, fdr; @@ -436,7 +431,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node, return; } - ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->real_clk); + ret = mpc_i2c_get_fdr_8xxx(node, clock, &i2c->real_clk); fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); @@ -450,7 +445,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node, #else /* !CONFIG_FSL_SOC */ static void mpc_i2c_setup_8xxx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { } #endif /* CONFIG_FSL_SOC */ @@ -721,11 +716,11 @@ static int fsl_i2c_probe(struct platform_device *op) if (match->data) { const struct mpc_i2c_data *data = match->data; - data->setup(op->dev.of_node, i2c, clock, data->prescaler); + data->setup(op->dev.of_node, i2c, clock); } else { /* Backwards compatibility */ if (of_get_property(op->dev.of_node, "dfsrr", NULL)) - mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0); + mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock); } prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen); @@ -823,12 +818,10 @@ static const struct mpc_i2c_data mpc_i2c_data_8313 = { static const struct mpc_i2c_data mpc_i2c_data_8543 = { .setup = mpc_i2c_setup_8xxx, - .prescaler = 2, }; static const struct mpc_i2c_data mpc_i2c_data_8544 = { .setup = mpc_i2c_setup_8xxx, - .prescaler = 3, }; static const struct of_device_id mpc_i2c_of_match[] = { -- cgit From 5cd5f0bb0d9c32876b3d86b70fb45da10d028be7 Mon Sep 17 00:00:00 2001 From: Radu Rendec Date: Thu, 4 Jan 2018 18:18:13 +0000 Subject: i2c: ismt: 16-byte align the DMA buffer address Use only a portion of the data buffer for DMA transfers, which is always 16-byte aligned. This makes the DMA buffer address 16-byte aligned and compensates for spurious hardware parity errors that may appear when the DMA buffer address is not 16-byte aligned. The data buffer is enlarged in order to accommodate any possible 16-byte alignment offset and changes the DMA code to only use a portion of the data buffer, which is 16-byte aligned. The symptom of the hardware issue is the same as the one addressed in v3.12-rc2-5-gbf41691 and manifests by transfers failing with EIO, with bit 9 being set in the ERRSTS register. Signed-off-by: Radu Rendec Acked-by: Neil Horman Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ismt.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 45ad9b847c58..0d1c3ec8cb40 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -172,7 +172,7 @@ struct ismt_priv { dma_addr_t io_rng_dma; /* descriptor HW base addr */ u8 head; /* ring buffer head pointer */ struct completion cmp; /* interrupt completion */ - u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */ + u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ }; /** @@ -320,7 +320,7 @@ static int ismt_process_desc(const struct ismt_desc *desc, struct ismt_priv *priv, int size, char read_write) { - u8 *dma_buffer = priv->dma_buffer; + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); __ismt_desc_dump(&priv->pci_dev->dev, desc); @@ -395,11 +395,12 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, struct ismt_desc *desc; struct ismt_priv *priv = i2c_get_adapdata(adap); struct device *dev = &priv->pci_dev->dev; + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); desc = &priv->hw[priv->head]; /* Initialize the DMA buffer */ - memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer)); + memset(priv->buffer, 0, sizeof(priv->buffer)); /* Initialize the descriptor */ memset(desc, 0, sizeof(struct ismt_desc)); @@ -448,8 +449,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->wr_len_cmd = 2; dma_size = 2; dma_direction = DMA_TO_DEVICE; - priv->dma_buffer[0] = command; - priv->dma_buffer[1] = data->byte; + dma_buffer[0] = command; + dma_buffer[1] = data->byte; } else { /* Read Byte */ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); @@ -468,9 +469,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->wr_len_cmd = 3; dma_size = 3; dma_direction = DMA_TO_DEVICE; - priv->dma_buffer[0] = command; - priv->dma_buffer[1] = data->word & 0xff; - priv->dma_buffer[2] = data->word >> 8; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; } else { /* Read Word */ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); @@ -488,9 +489,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->rd_len = 2; dma_size = 3; dma_direction = DMA_BIDIRECTIONAL; - priv->dma_buffer[0] = command; - priv->dma_buffer[1] = data->word & 0xff; - priv->dma_buffer[2] = data->word >> 8; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; break; case I2C_SMBUS_BLOCK_DATA: @@ -501,8 +502,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, dma_direction = DMA_TO_DEVICE; desc->wr_len_cmd = dma_size; desc->control |= ISMT_DESC_BLK; - priv->dma_buffer[0] = command; - memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); } else { /* Block Read */ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); @@ -529,8 +530,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, dma_direction = DMA_TO_DEVICE; desc->wr_len_cmd = dma_size; desc->control |= ISMT_DESC_I2C; - priv->dma_buffer[0] = command; - memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); } else { /* i2c Block Read */ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); @@ -559,18 +560,18 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, if (dma_size != 0) { dev_dbg(dev, " dev=%p\n", dev); dev_dbg(dev, " data=%p\n", data); - dev_dbg(dev, " dma_buffer=%p\n", priv->dma_buffer); + dev_dbg(dev, " dma_buffer=%p\n", dma_buffer); dev_dbg(dev, " dma_size=%d\n", dma_size); dev_dbg(dev, " dma_direction=%d\n", dma_direction); dma_addr = dma_map_single(dev, - priv->dma_buffer, + dma_buffer, dma_size, dma_direction); if (dma_mapping_error(dev, dma_addr)) { dev_err(dev, "Error in mapping dma buffer %p\n", - priv->dma_buffer); + dma_buffer); return -EIO; } -- cgit From c75886862480bb243833e94292db9c44b8af9868 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 2 Jan 2018 12:06:27 -0800 Subject: lkdtm/usercopy: Adjust test to include an offset to check reporting Instead of doubling the size, push the start position up by 16 bytes to still trigger an overflow. This allows to verify that offset reporting is working correctly. Signed-off-by: Kees Cook --- drivers/misc/lkdtm_usercopy.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm_usercopy.c b/drivers/misc/lkdtm_usercopy.c index a64372cc148d..9ebbb031e5e3 100644 --- a/drivers/misc/lkdtm_usercopy.c +++ b/drivers/misc/lkdtm_usercopy.c @@ -119,6 +119,8 @@ static void do_usercopy_heap_size(bool to_user) { unsigned long user_addr; unsigned char *one, *two; + void __user *test_user_addr; + void *test_kern_addr; size_t size = unconst + 1024; one = kmalloc(size, GFP_KERNEL); @@ -139,27 +141,30 @@ static void do_usercopy_heap_size(bool to_user) memset(one, 'A', size); memset(two, 'B', size); + test_user_addr = (void __user *)(user_addr + 16); + test_kern_addr = one + 16; + if (to_user) { pr_info("attempting good copy_to_user of correct size\n"); - if (copy_to_user((void __user *)user_addr, one, size)) { + if (copy_to_user(test_user_addr, test_kern_addr, size / 2)) { pr_warn("copy_to_user failed unexpectedly?!\n"); goto free_user; } pr_info("attempting bad copy_to_user of too large size\n"); - if (copy_to_user((void __user *)user_addr, one, 2 * size)) { + if (copy_to_user(test_user_addr, test_kern_addr, size)) { pr_warn("copy_to_user failed, but lacked Oops\n"); goto free_user; } } else { pr_info("attempting good copy_from_user of correct size\n"); - if (copy_from_user(one, (void __user *)user_addr, size)) { + if (copy_from_user(test_kern_addr, test_user_addr, size / 2)) { pr_warn("copy_from_user failed unexpectedly?!\n"); goto free_user; } pr_info("attempting bad copy_from_user of too large size\n"); - if (copy_from_user(one, (void __user *)user_addr, 2 * size)) { + if (copy_from_user(test_kern_addr, test_user_addr, size)) { pr_warn("copy_from_user failed, but lacked Oops\n"); goto free_user; } -- cgit From 0afe76e88c57d91ef5697720aed380a339e3df70 Mon Sep 17 00:00:00 2001 From: David Windsor Date: Sat, 10 Jun 2017 22:50:45 -0400 Subject: scsi: Define usercopy region in scsi_sense_cache slab cache SCSI sense buffers, stored in struct scsi_cmnd.sense and therefore contained in the scsi_sense_cache slab cache, need to be copied to/from userspace. cache object allocation: drivers/scsi/scsi_lib.c: scsi_select_sense_cache(...): return ... ? scsi_sense_isadma_cache : scsi_sense_cache scsi_alloc_sense_buffer(...): return kmem_cache_alloc_node(scsi_select_sense_cache(), ...); scsi_init_request(...): ... cmd->sense_buffer = scsi_alloc_sense_buffer(...); ... cmd->req.sense = cmd->sense_buffer example usage trace: block/scsi_ioctl.c: (inline from sg_io) blk_complete_sghdr_rq(...): struct scsi_request *req = scsi_req(rq); ... copy_to_user(..., req->sense, len) scsi_cmd_ioctl(...): sg_io(...); In support of usercopy hardening, this patch defines a region in the scsi_sense_cache slab cache in which userspace copy operations are allowed. This region is known as the slab cache's usercopy region. Slab caches can now check that each dynamically sized copy operation involving cache-managed memory falls entirely within the slab's usercopy region. Signed-off-by: David Windsor [kees: adjust commit log, provide usage trace] Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: linux-scsi@vger.kernel.org Signed-off-by: Kees Cook --- drivers/scsi/scsi_lib.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 1cbc497e00bd..164d062c4d94 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -79,14 +79,15 @@ int scsi_init_sense_cache(struct Scsi_Host *shost) if (shost->unchecked_isa_dma) { scsi_sense_isadma_cache = kmem_cache_create("scsi_sense_cache(DMA)", - SCSI_SENSE_BUFFERSIZE, 0, - SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL); + SCSI_SENSE_BUFFERSIZE, 0, + SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL); if (!scsi_sense_isadma_cache) ret = -ENOMEM; } else { scsi_sense_cache = - kmem_cache_create("scsi_sense_cache", - SCSI_SENSE_BUFFERSIZE, 0, SLAB_HWCACHE_ALIGN, NULL); + kmem_cache_create_usercopy("scsi_sense_cache", + SCSI_SENSE_BUFFERSIZE, 0, SLAB_HWCACHE_ALIGN, + 0, SCSI_SENSE_BUFFERSIZE, NULL); if (!scsi_sense_cache) ret = -ENOMEM; } -- cgit From e47e311843dece8073146f3606871280ee9beb87 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 14 Jun 2017 18:56:55 -0700 Subject: lkdtm: Update usercopy tests for whitelisting This updates the USERCOPY_HEAP_FLAG_* tests to USERCOPY_HEAP_WHITELIST_*, since the final form of usercopy whitelisting ended up using an offset/size window instead of the earlier proposed allocation flags. Signed-off-by: Kees Cook --- drivers/misc/lkdtm.h | 4 +- drivers/misc/lkdtm_core.c | 4 +- drivers/misc/lkdtm_usercopy.c | 88 ++++++++++++++++++++++++------------------- 3 files changed, 53 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index 687a0dbbe199..9e513dcfd809 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -76,8 +76,8 @@ void __init lkdtm_usercopy_init(void); void __exit lkdtm_usercopy_exit(void); void lkdtm_USERCOPY_HEAP_SIZE_TO(void); void lkdtm_USERCOPY_HEAP_SIZE_FROM(void); -void lkdtm_USERCOPY_HEAP_FLAG_TO(void); -void lkdtm_USERCOPY_HEAP_FLAG_FROM(void); +void lkdtm_USERCOPY_HEAP_WHITELIST_TO(void); +void lkdtm_USERCOPY_HEAP_WHITELIST_FROM(void); void lkdtm_USERCOPY_STACK_FRAME_TO(void); void lkdtm_USERCOPY_STACK_FRAME_FROM(void); void lkdtm_USERCOPY_STACK_BEYOND(void); diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index ba92291508dc..e3f2bac4b245 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -177,8 +177,8 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(ATOMIC_TIMING), CRASHTYPE(USERCOPY_HEAP_SIZE_TO), CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), - CRASHTYPE(USERCOPY_HEAP_FLAG_TO), - CRASHTYPE(USERCOPY_HEAP_FLAG_FROM), + CRASHTYPE(USERCOPY_HEAP_WHITELIST_TO), + CRASHTYPE(USERCOPY_HEAP_WHITELIST_FROM), CRASHTYPE(USERCOPY_STACK_FRAME_TO), CRASHTYPE(USERCOPY_STACK_FRAME_FROM), CRASHTYPE(USERCOPY_STACK_BEYOND), diff --git a/drivers/misc/lkdtm_usercopy.c b/drivers/misc/lkdtm_usercopy.c index 9ebbb031e5e3..9725aed305bb 100644 --- a/drivers/misc/lkdtm_usercopy.c +++ b/drivers/misc/lkdtm_usercopy.c @@ -20,7 +20,7 @@ */ static volatile size_t unconst = 0; static volatile size_t cache_size = 1024; -static struct kmem_cache *bad_cache; +static struct kmem_cache *whitelist_cache; static const unsigned char test_text[] = "This is a test.\n"; @@ -115,6 +115,10 @@ free_user: vm_munmap(user_addr, PAGE_SIZE); } +/* + * This checks for whole-object size validation with hardened usercopy, + * with or without usercopy whitelisting. + */ static void do_usercopy_heap_size(bool to_user) { unsigned long user_addr; @@ -177,77 +181,79 @@ free_kernel: kfree(two); } -static void do_usercopy_heap_flag(bool to_user) +/* + * This checks for the specific whitelist window within an object. If this + * test passes, then do_usercopy_heap_size() tests will pass too. + */ +static void do_usercopy_heap_whitelist(bool to_user) { - unsigned long user_addr; - unsigned char *good_buf = NULL; - unsigned char *bad_buf = NULL; + unsigned long user_alloc; + unsigned char *buf = NULL; + unsigned char __user *user_addr; + size_t offset, size; /* Make sure cache was prepared. */ - if (!bad_cache) { + if (!whitelist_cache) { pr_warn("Failed to allocate kernel cache\n"); return; } /* - * Allocate one buffer from each cache (kmalloc will have the - * SLAB_USERCOPY flag already, but "bad_cache" won't). + * Allocate a buffer with a whitelisted window in the buffer. */ - good_buf = kmalloc(cache_size, GFP_KERNEL); - bad_buf = kmem_cache_alloc(bad_cache, GFP_KERNEL); - if (!good_buf || !bad_buf) { - pr_warn("Failed to allocate buffers from caches\n"); + buf = kmem_cache_alloc(whitelist_cache, GFP_KERNEL); + if (!buf) { + pr_warn("Failed to allocate buffer from whitelist cache\n"); goto free_alloc; } /* Allocate user memory we'll poke at. */ - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + user_alloc = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { + if (user_alloc >= TASK_SIZE) { pr_warn("Failed to allocate user memory\n"); goto free_alloc; } + user_addr = (void __user *)user_alloc; - memset(good_buf, 'A', cache_size); - memset(bad_buf, 'B', cache_size); + memset(buf, 'B', cache_size); + + /* Whitelisted window in buffer, from kmem_cache_create_usercopy. */ + offset = (cache_size / 4) + unconst; + size = (cache_size / 16) + unconst; if (to_user) { - pr_info("attempting good copy_to_user with SLAB_USERCOPY\n"); - if (copy_to_user((void __user *)user_addr, good_buf, - cache_size)) { + pr_info("attempting good copy_to_user inside whitelist\n"); + if (copy_to_user(user_addr, buf + offset, size)) { pr_warn("copy_to_user failed unexpectedly?!\n"); goto free_user; } - pr_info("attempting bad copy_to_user w/o SLAB_USERCOPY\n"); - if (copy_to_user((void __user *)user_addr, bad_buf, - cache_size)) { + pr_info("attempting bad copy_to_user outside whitelist\n"); + if (copy_to_user(user_addr, buf + offset - 1, size)) { pr_warn("copy_to_user failed, but lacked Oops\n"); goto free_user; } } else { - pr_info("attempting good copy_from_user with SLAB_USERCOPY\n"); - if (copy_from_user(good_buf, (void __user *)user_addr, - cache_size)) { + pr_info("attempting good copy_from_user inside whitelist\n"); + if (copy_from_user(buf + offset, user_addr, size)) { pr_warn("copy_from_user failed unexpectedly?!\n"); goto free_user; } - pr_info("attempting bad copy_from_user w/o SLAB_USERCOPY\n"); - if (copy_from_user(bad_buf, (void __user *)user_addr, - cache_size)) { + pr_info("attempting bad copy_from_user outside whitelist\n"); + if (copy_from_user(buf + offset - 1, user_addr, size)) { pr_warn("copy_from_user failed, but lacked Oops\n"); goto free_user; } } free_user: - vm_munmap(user_addr, PAGE_SIZE); + vm_munmap(user_alloc, PAGE_SIZE); free_alloc: - if (bad_buf) - kmem_cache_free(bad_cache, bad_buf); - kfree(good_buf); + if (buf) + kmem_cache_free(whitelist_cache, buf); } /* Callable tests. */ @@ -261,14 +267,14 @@ void lkdtm_USERCOPY_HEAP_SIZE_FROM(void) do_usercopy_heap_size(false); } -void lkdtm_USERCOPY_HEAP_FLAG_TO(void) +void lkdtm_USERCOPY_HEAP_WHITELIST_TO(void) { - do_usercopy_heap_flag(true); + do_usercopy_heap_whitelist(true); } -void lkdtm_USERCOPY_HEAP_FLAG_FROM(void) +void lkdtm_USERCOPY_HEAP_WHITELIST_FROM(void) { - do_usercopy_heap_flag(false); + do_usercopy_heap_whitelist(false); } void lkdtm_USERCOPY_STACK_FRAME_TO(void) @@ -319,11 +325,15 @@ free_user: void __init lkdtm_usercopy_init(void) { /* Prepare cache that lacks SLAB_USERCOPY flag. */ - bad_cache = kmem_cache_create("lkdtm-no-usercopy", cache_size, 0, - 0, NULL); + whitelist_cache = + kmem_cache_create_usercopy("lkdtm-usercopy", cache_size, + 0, 0, + cache_size / 4, + cache_size / 16, + NULL); } void __exit lkdtm_usercopy_exit(void) { - kmem_cache_destroy(bad_cache); + kmem_cache_destroy(whitelist_cache); } -- cgit From 4d3ea4e1c3841e88704958ee2600adb39f30fbcd Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 30 Nov 2017 15:30:05 +0100 Subject: i2c: exynos5: change internal transmission timeout to 100ms Exynos-I2C uses default timeout of 1 second for the whole transaction, including re-transmissions due to arbitration lost errors (-EAGAIN). To allow re-transmissions driver's internal timeout should be significantly lower, 100ms seems to be good candidate. Signed-off-by: Andrzej Hajda Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 3855e0b11877..b02428498f6d 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -170,7 +170,7 @@ #define HSI2C_HS_TX_CLOCK 1000000 #define HSI2C_FS_TX_CLOCK 100000 -#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) +#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100)) #define HSI2C_EXYNOS7 BIT(0) -- cgit From 8092178ffe67dbd1f987e2e308e871c774774a16 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 9 Jan 2018 14:58:56 +0100 Subject: i2c: add 'set_sda' to bus_recovery_info This will be needed when we want to create STOP conditions, too, later. Create the needed fields and populate them for the GPIO case if the GPIO is set to output. Tested-by: Phil Reid Signed-off-by: Wolfram Sang Reviewed-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index bb34a5d41133..a8b3fbe16fa0 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -147,6 +147,11 @@ static int get_sda_gpio_value(struct i2c_adapter *adap) return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } +static void set_sda_gpio_value(struct i2c_adapter *adap, int val) +{ + gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val); +} + /* * We are generating clock pulses. ndelay() determines durating of clk pulses. * We will generate clock with rate 100 KHz and so duration of both clock levels @@ -225,8 +230,12 @@ static void i2c_init_recovery(struct i2c_adapter *adap) if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_recovery) { bri->get_scl = get_scl_gpio_value; bri->set_scl = set_scl_gpio_value; - if (bri->sda_gpiod) + if (bri->sda_gpiod) { bri->get_sda = get_sda_gpio_value; + /* FIXME: add proper flag instead of '0' once available */ + if (gpiod_get_direction(bri->sda_gpiod) == 0) + bri->set_sda = set_sda_gpio_value; + } return; } -- cgit From 72b08fcc15dc6a2d211880e4dc7cf5314e9ab750 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 9 Jan 2018 14:58:57 +0100 Subject: i2c: ensure SDA is released in recovery if SDA is controllable If we have a function to control SDA, we should ensure that SDA is not held down by us. So, release the GPIO in this case. Tested-by: Phil Reid Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index a8b3fbe16fa0..54cef80990a1 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -169,6 +169,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap) bri->prepare_recovery(adap); bri->set_scl(adap, val); + if (bri->set_sda) + bri->set_sda(adap, 1); ndelay(RECOVERY_NDELAY); /* -- cgit From 2806e6ad77c71dd2538cb698aad476e8cf3af004 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 9 Jan 2018 14:58:58 +0100 Subject: i2c: send STOP after successful bus recovery If we managed to get a client release SDA again, send a STOP afterwards to make sure we have a consistent state on the bus again. Tested-by: Phil Reid Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 54cef80990a1..23f353630db3 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -199,6 +199,18 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap) if (bri->get_sda && !bri->get_sda(adap)) ret = -EBUSY; + /* If all went well, send STOP for a sane bus state. */ + if (ret == 0 && bri->set_sda) { + bri->set_scl(adap, 0); + ndelay(RECOVERY_NDELAY / 2); + bri->set_sda(adap, 0); + ndelay(RECOVERY_NDELAY / 2); + bri->set_scl(adap, 1); + ndelay(RECOVERY_NDELAY / 2); + bri->set_sda(adap, 1); + ndelay(RECOVERY_NDELAY / 2); + } + if (bri->unprepare_recovery) bri->unprepare_recovery(adap); -- cgit From 7d2c17f021c656a9429df05e27a359041c1bada8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 9 Jan 2018 14:58:59 +0100 Subject: i2c: rcar: implement bus recovery We can force levels of SCL and SDA, so we can use that for bus recovery. Note that we cannot read SDA back, because we will only get the internal state of the bus free detection. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 54 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 8a2ae3e6c561..d4b7b5380c29 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -132,6 +132,7 @@ struct rcar_i2c_priv { int pos; u32 icccr; u32 flags; + u8 recovery_icmcr; /* protected by adapter lock */ enum rcar_i2c_type devtype; struct i2c_client *slave; @@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) return readl(priv->io + reg); } +static int rcar_i2c_get_scl(struct i2c_adapter *adap) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + return !!(rcar_i2c_read(priv, ICMCR) & FSCL); + +}; + +static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + if (val) + priv->recovery_icmcr |= FSCL; + else + priv->recovery_icmcr &= ~FSCL; + + rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); +}; + +/* No get_sda, because the HW only reports its bus free logic, not SDA itself */ + +static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + if (val) + priv->recovery_icmcr |= FSDA; + else + priv->recovery_icmcr &= ~FSDA; + + rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); +}; + +static struct i2c_bus_recovery_info rcar_i2c_bri = { + .get_scl = rcar_i2c_get_scl, + .set_scl = rcar_i2c_set_scl, + .set_sda = rcar_i2c_set_sda, + .recover_bus = i2c_generic_scl_recovery, +}; static void rcar_i2c_init(struct rcar_i2c_priv *priv) { /* reset master mode */ @@ -170,7 +211,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) { - int i; + int i, ret; for (i = 0; i < LOOP_TIMEOUT; i++) { /* make sure that bus is not busy */ @@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) udelay(1); } - return -EBUSY; + /* Waiting did not help, try to recover */ + priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; + ret = i2c_recover_bus(&priv->adap); + + /* No failure when recovering, so check bus busy bit again */ + if (ret == 0) + ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0; + + return ret; } static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) @@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) adap->retries = 3; adap->dev.parent = dev; adap->dev.of_node = dev->of_node; + adap->bus_recovery_info = &rcar_i2c_bri; i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); -- cgit From 02c9d285ff321c306a321b5f7df054d194dec52f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 13 Jan 2018 11:04:29 +0100 Subject: pinctrl: abx500: Use seq_putc() in abx500_gpio_dbg_show() A single character (line break) should be put into a sequence. Thus use the corresponding function "seq_putc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 7d00a5d864f5..d56a49e53f56 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -633,7 +633,7 @@ static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) for (i = 0; i < chip->ngpio; i++, gpio++) { /* On AB8500, there is no GPIO0, the first is the GPIO 1 */ abx500_gpio_dbg_show_one(s, pctldev, chip, i + 1, gpio); - seq_printf(s, "\n"); + seq_putc(s, '\n'); } } -- cgit From ffd10c2ec771dde7005d29a255d943152311006d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 13 Jan 2018 11:33:47 +0100 Subject: pinctrl: pinmux: Use seq_putc() in pinmux_pins_show() A single character (line break) should be put into a sequence. Thus use the corresponding function "seq_putc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/pinmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 82b18ef44ee4..b8e9bda8ec98 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -617,7 +617,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what) pctlops->get_group_name(pctldev, desc->mux_setting->group)); else - seq_printf(s, "\n"); + seq_putc(s, '\n'); } mutex_unlock(&pctldev->mutex); -- cgit From 9d2fc7c37099f741c860733272ec12cd9829c230 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 13 Jan 2018 12:42:14 +0100 Subject: pinctrl: sprd: Use seq_putc() in sprd_pinconf_group_dbg_show() A single character (line break) should be put into a sequence. Thus use the corresponding function "seq_putc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/pinctrl/sprd/pinctrl-sprd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sprd/pinctrl-sprd.c b/drivers/pinctrl/sprd/pinctrl-sprd.c index 63529911445c..ba1c2ca406e4 100644 --- a/drivers/pinctrl/sprd/pinctrl-sprd.c +++ b/drivers/pinctrl/sprd/pinctrl-sprd.c @@ -818,7 +818,7 @@ static void sprd_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, grp = &info->groups[selector]; - seq_printf(s, "\n"); + seq_putc(s, '\n'); for (i = 0; i < grp->npins; i++, config++) { unsigned int pin_id = grp->pins[i]; -- cgit From e199c285b66705bec2f63a9230f50dadfa6dc0fb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 15 Jan 2018 21:28:39 +0100 Subject: i2c: acorn: add MODULE_LICENSE tag As of v4.15, Kbuild warns about missing MODULE_LICENSE tags: WARNING: modpost: missing MODULE_LICENSE() in drivers/i2c/busses/i2c-acorn.o This adds a license, author and description tag, matching the comment at the start of the acorn i2c driver. Signed-off-by: Arnd Bergmann Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-acorn.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index 9d7be5af2bf2..a6f22d30a288 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -94,3 +94,7 @@ static int __init i2c_ioc_init(void) } module_init(i2c_ioc_init); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver"); +MODULE_LICENSE("GPL v2"); -- cgit From f89813ec8ba4b46c7926325eb9835ef1c6793496 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 15 Jan 2018 18:41:39 +0100 Subject: i2c: acorn: remove outdated path from file header That path has gone away for a long time. Move the HW name upwards for a proper header. Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-acorn.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index a6f22d30a288..f4a5ae69bf6a 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -1,5 +1,5 @@ /* - * linux/drivers/acorn/char/i2c.c + * ARM IOC/IOMD i2c driver. * * Copyright (C) 2000 Russell King * @@ -7,8 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * ARM IOC/IOMD i2c driver. - * * On Acorn machines, the following i2c devices are on the bus: * - PCF8583 real time clock & static RAM */ -- cgit From d032a2eb2e3b9fc2def41c22bfb58e1efc2c6823 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 2 Jan 2018 14:28:03 +0100 Subject: i2c: rk3x: account for const type of of_device_id.data This driver creates a number of const structures that it stores in the data field of an of_device_id array. The data field of an of_device_id structure has type const void *, so there is no need for a const-discarding cast when putting const values into such a structure. Furthermore, adding const to the declaration of the location that receives a const value from such a field ensures that the compiler will continue to check that the value is not modified. The const-discarding cast on the extraction from the data field is thus no longer needed. Done using Coccinelle. Signed-off-by: Julia Lawall Reviewed-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index fe234578380a..1f80960c5ae1 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -194,7 +194,7 @@ struct rk3x_i2c_soc_data { struct rk3x_i2c { struct i2c_adapter adap; struct device *dev; - struct rk3x_i2c_soc_data *soc_data; + const struct rk3x_i2c_soc_data *soc_data; /* Hardware resources */ void __iomem *regs; @@ -1164,27 +1164,27 @@ static const struct rk3x_i2c_soc_data rk3399_soc_data = { static const struct of_device_id rk3x_i2c_match[] = { { .compatible = "rockchip,rv1108-i2c", - .data = (void *)&rv1108_soc_data + .data = &rv1108_soc_data }, { .compatible = "rockchip,rk3066-i2c", - .data = (void *)&rk3066_soc_data + .data = &rk3066_soc_data }, { .compatible = "rockchip,rk3188-i2c", - .data = (void *)&rk3188_soc_data + .data = &rk3188_soc_data }, { .compatible = "rockchip,rk3228-i2c", - .data = (void *)&rk3228_soc_data + .data = &rk3228_soc_data }, { .compatible = "rockchip,rk3288-i2c", - .data = (void *)&rk3288_soc_data + .data = &rk3288_soc_data }, { .compatible = "rockchip,rk3399-i2c", - .data = (void *)&rk3399_soc_data + .data = &rk3399_soc_data }, {}, }; @@ -1207,7 +1207,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev) return -ENOMEM; match = of_match_node(rk3x_i2c_match, np); - i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data; + i2c->soc_data = match->data; /* use common interface to get I2C timing properties */ i2c_parse_fw_timings(&pdev->dev, &i2c->t, true); -- cgit From 5bacb56b2b56283ab26fea9e15f06ebe27afbe3d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Jan 2018 00:18:17 +0100 Subject: i2c: rk3x: add proper kerneldoc header gcc noticed the kerneldoc was wrongly formatted. Fix it! drivers/i2c/busses/i2c-rk3x.c:164: warning: Cannot understand * @grf_offset: ... on line 164 - I thought it was a doc line Signed-off-by: Wolfram Sang Reviewed-by: Heiko Stuebner --- drivers/i2c/busses/i2c-rk3x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 1f80960c5ae1..e1a18d989f83 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -161,6 +161,7 @@ enum rk3x_i2c_state { }; /** + * struct rk3x_i2c_soc_data: * @grf_offset: offset inside the grf regmap for setting the i2c type * @calc_timings: Callback function for i2c timing information calculated */ -- cgit From f1343d044629f11e7d63ef1a07edb1db585302e0 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 17 Nov 2017 02:00:51 +1000 Subject: cpuidle/powernv: avoid double irq enable coming out of idle Since e1689795a7 ("cpuidle: Add common time keeping and irq enabling"), cpuidle drivers are expected to return from ->enter with irqs disabled. Update the cpuidle-powernv snooze loop to disable irqs before returning. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/cpuidle/cpuidle-powernv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index e06605b21841..1a8234e706bc 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -76,6 +76,8 @@ static int snooze_loop(struct cpuidle_device *dev, ppc64_runlatch_on(); clear_thread_flag(TIF_POLLING_NRFLAG); + local_irq_disable(); + return index; } -- cgit From ced54c08d8e4060d59c10629ea5a4ccdaed6898e Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 17 Nov 2017 02:00:52 +1000 Subject: cpuidle/powernv: avoid double irq enable coming out of idle Since e1689795a7 ("cpuidle: Add common time keeping and irq enabling"), cpuidle drivers are expected to return from ->enter with irqs disabled. Update the cpuidle-powernv snooze and cede loops to disable irqs before returning. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/cpuidle/cpuidle-pseries.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c index a187a39fb866..0f2b697cbb27 100644 --- a/drivers/cpuidle/cpuidle-pseries.c +++ b/drivers/cpuidle/cpuidle-pseries.c @@ -51,8 +51,6 @@ static inline void idle_loop_epilog(unsigned long in_purr) get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles); get_lppaca()->idle = 0; - if (irqs_disabled()) - local_irq_enable(); ppc64_runlatch_on(); } @@ -87,6 +85,8 @@ static int snooze_loop(struct cpuidle_device *dev, HMT_medium(); clear_thread_flag(TIF_POLLING_NRFLAG); + local_irq_disable(); + idle_loop_epilog(in_purr); return index; @@ -121,6 +121,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, HMT_medium(); check_and_cede_processor(); + local_irq_disable(); get_lppaca()->donate_dedicated_cpu = 0; idle_loop_epilog(in_purr); @@ -145,6 +146,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, */ check_and_cede_processor(); + local_irq_disable(); idle_loop_epilog(in_purr); return index; -- cgit From f2ac428e0edabbca41b9dfe9473a90147962e4e9 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 10 Oct 2017 17:11:09 +1000 Subject: powerpc/pseries/cpuidle: add polling idle for shared processor guests For shared processor guests (e.g., KVM), add an idle polling mode rather than immediately returning to the hypervisor when the guest CPU goes idle. Test setup is a 2 socket POWER9 with 4 guests running, each with vCPUs equal to 1/2 of real of CPUs. Saturated each guest with tbench. Using polling idle gives about 1.4x throughput. Kernel compile speed was not changed significantly. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/cpuidle/cpuidle-pseries.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c index 0f2b697cbb27..9e56bc411061 100644 --- a/drivers/cpuidle/cpuidle-pseries.c +++ b/drivers/cpuidle/cpuidle-pseries.c @@ -174,11 +174,17 @@ static struct cpuidle_state dedicated_states[] = { * States for shared partition case. */ static struct cpuidle_state shared_states[] = { + { /* Snooze */ + .name = "snooze", + .desc = "snooze", + .exit_latency = 0, + .target_residency = 0, + .enter = &snooze_loop }, { /* Shared Cede */ .name = "Shared Cede", .desc = "Shared Cede", - .exit_latency = 0, - .target_residency = 0, + .exit_latency = 10, + .target_residency = 100, .enter = &shared_cede_loop }, }; -- cgit From 119fcf47fdb7c672e328cd3e5b6a9a42f0c5ffd1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Jan 2018 11:29:17 +0000 Subject: pinctrl: ingenic: Remove redundant dev_err call in ingenic_pinctrl_probe() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-ingenic.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index 372ddf386bdb..ac38a3f9f86b 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -736,10 +736,8 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev) base = devm_ioremap_resource(dev, platform_get_resource(pdev, IORESOURCE_MEM, 0)); - if (IS_ERR(base)) { - dev_err(dev, "Failed to ioremap registers\n"); + if (IS_ERR(base)) return PTR_ERR(base); - } jzpc->map = devm_regmap_init_mmio(dev, base, &ingenic_pinctrl_regmap_config); -- cgit From 0657cb50b5a75abd92956028727dc255d690a4a6 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 17 Jan 2018 14:34:21 +0100 Subject: pinctrl: sx150x: Unregister the pinctrl on release There is no matching call to pinctrl_unregister, so switch to the managed devm_pinctrl_register to clean up properly when done. Cc: stable@vger.kernel.org Fixes: 9e80f9064e73 ("pinctrl: Add SX150X GPIO Extender Pinctrl Driver") Signed-off-by: Peter Rosin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-sx150x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index fb242c542dc9..f926ba044577 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -1225,7 +1225,7 @@ static int sx150x_probe(struct i2c_client *client, pctl->pinctrl_desc.npins = pctl->data->npins; pctl->pinctrl_desc.owner = THIS_MODULE; - pctl->pctldev = pinctrl_register(&pctl->pinctrl_desc, dev, pctl); + pctl->pctldev = devm_pinctrl_register(dev, &pctl->pinctrl_desc, pctl); if (IS_ERR(pctl->pctldev)) { dev_err(dev, "Failed to register pinctrl device\n"); return PTR_ERR(pctl->pctldev); -- cgit From 1a1d39e1b8dd1d0f92a79da4fcc1ab0be3ae9bfc Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 17 Jan 2018 14:34:22 +0100 Subject: pinctrl: sx150x: Register pinctrl before adding the gpiochip Various gpiolib activity depend on the pinctrl to be up and kicking. Therefore, register the pinctrl before adding a gpiochip. Cc: stable@vger.kernel.org Suggested-by: Linus Walleij Signed-off-by: Peter Rosin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-sx150x.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index f926ba044577..049dd15e04ef 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -1144,6 +1144,27 @@ static int sx150x_probe(struct i2c_client *client, if (ret) return ret; + /* Pinctrl_desc */ + pctl->pinctrl_desc.name = "sx150x-pinctrl"; + pctl->pinctrl_desc.pctlops = &sx150x_pinctrl_ops; + pctl->pinctrl_desc.confops = &sx150x_pinconf_ops; + pctl->pinctrl_desc.pins = pctl->data->pins; + pctl->pinctrl_desc.npins = pctl->data->npins; + pctl->pinctrl_desc.owner = THIS_MODULE; + + ret = devm_pinctrl_register_and_init(dev, &pctl->pinctrl_desc, + pctl, &pctl->pctldev); + if (ret) { + dev_err(dev, "Failed to register pinctrl device\n"); + return ret; + } + + ret = pinctrl_enable(pctl->pctldev); + if (ret) { + dev_err(dev, "Failed to enable pinctrl device\n"); + return ret; + } + /* Register GPIO controller */ pctl->gpio.label = devm_kstrdup(dev, client->name, GFP_KERNEL); pctl->gpio.base = -1; @@ -1217,20 +1238,6 @@ static int sx150x_probe(struct i2c_client *client, client->irq); } - /* Pinctrl_desc */ - pctl->pinctrl_desc.name = "sx150x-pinctrl"; - pctl->pinctrl_desc.pctlops = &sx150x_pinctrl_ops; - pctl->pinctrl_desc.confops = &sx150x_pinconf_ops; - pctl->pinctrl_desc.pins = pctl->data->pins; - pctl->pinctrl_desc.npins = pctl->data->npins; - pctl->pinctrl_desc.owner = THIS_MODULE; - - pctl->pctldev = devm_pinctrl_register(dev, &pctl->pinctrl_desc, pctl); - if (IS_ERR(pctl->pctldev)) { - dev_err(dev, "Failed to register pinctrl device\n"); - return PTR_ERR(pctl->pctldev); - } - return 0; } -- cgit From b930151e5b55a0e62a3aad06876de891ac980471 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 17 Jan 2018 14:34:23 +0100 Subject: pinctrl: sx150x: Add a static gpio/pinctrl pin range mapping Without such a range, gpiolib fails with -EPROBE_DEFER, pending the addition of the range. So, without a range, gpiolib will keep deferring indefinitely. Cc: stable@vger.kernel.org Fixes: 9e80f9064e73 ("pinctrl: Add SX150X GPIO Extender Pinctrl Driver") Fixes: e10f72bf4b3e ("gpio: gpiolib: Generalise state persistence beyond sleep") Suggested-by: Linus Walleij Signed-off-by: Peter Rosin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-sx150x.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index 049dd15e04ef..cbf58a10113d 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -1193,6 +1193,11 @@ static int sx150x_probe(struct i2c_client *client, if (ret) return ret; + ret = gpiochip_add_pin_range(&pctl->gpio, dev_name(dev), + 0, 0, pctl->data->npins); + if (ret) + return ret; + /* Add Interrupt support if an irq is specified */ if (client->irq > 0) { pctl->irq_chip.name = devm_kstrdup(dev, client->name, -- cgit From 4402be2b4ca7f53b6213a9e6b3abe9cdcc683e9b Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 18 Jan 2018 21:08:46 +0100 Subject: rtc: remove rtc-at32ap700x Since PLATFORM_AT32AP is an AVR32 platform which was removed, the rtc driver rtc-at32ap700x is useless. This patch remove it. Signed-off-by: Corentin Labbe Acked-by: Hans-Christian Noren Egtvedt Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 7 -- drivers/rtc/Makefile | 1 - drivers/rtc/rtc-at32ap700x.c | 287 ------------------------------------------- 3 files changed, 295 deletions(-) delete mode 100644 drivers/rtc/rtc-at32ap700x.c (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b71cc7b5fbc9..8ab5f0a5d323 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1402,13 +1402,6 @@ config RTC_DRV_PL031 To compile this driver as a module, choose M here: the module will be called rtc-pl031. -config RTC_DRV_AT32AP700X - tristate "AT32AP700X series RTC" - depends on PLATFORM_AT32AP || COMPILE_TEST - help - Driver for the internal RTC (Realtime Clock) on Atmel AVR32 - AT32AP700x family processors. - config RTC_DRV_AT91RM9200 tristate "AT91RM9200 or some AT91SAM9 RTC" depends on ARCH_AT91 || COMPILE_TEST diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6dfbbe9cd8a2..4fbf87e45a7c 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o -obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c deleted file mode 100644 index de8bf56a41e7..000000000000 --- a/drivers/rtc/rtc-at32ap700x.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * An RTC driver for the AVR32 AT32AP700x processor series. - * - * Copyright (C) 2007 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -/* - * This is a bare-bones RTC. It runs during most system sleep states, but has - * no battery backup and gets reset during system restart. It must be - * initialized from an external clock (network, I2C, etc) before it can be of - * much use. - * - * The alarm functionality is limited by the hardware, not supporting - * periodic interrupts. - */ - -#define RTC_CTRL 0x00 -#define RTC_CTRL_EN 0 -#define RTC_CTRL_PCLR 1 -#define RTC_CTRL_TOPEN 2 -#define RTC_CTRL_PSEL 8 - -#define RTC_VAL 0x04 - -#define RTC_TOP 0x08 - -#define RTC_IER 0x10 -#define RTC_IER_TOPI 0 - -#define RTC_IDR 0x14 -#define RTC_IDR_TOPI 0 - -#define RTC_IMR 0x18 -#define RTC_IMR_TOPI 0 - -#define RTC_ISR 0x1c -#define RTC_ISR_TOPI 0 - -#define RTC_ICR 0x20 -#define RTC_ICR_TOPI 0 - -#define RTC_BIT(name) (1 << RTC_##name) -#define RTC_BF(name, value) ((value) << RTC_##name) - -#define rtc_readl(dev, reg) \ - __raw_readl((dev)->regs + RTC_##reg) -#define rtc_writel(dev, reg, value) \ - __raw_writel((value), (dev)->regs + RTC_##reg) - -struct rtc_at32ap700x { - struct rtc_device *rtc; - void __iomem *regs; - unsigned long alarm_time; - unsigned long irq; - /* Protect against concurrent register access. */ - spinlock_t lock; -}; - -static int at32_rtc_readtime(struct device *dev, struct rtc_time *tm) -{ - struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); - unsigned long now; - - now = rtc_readl(rtc, VAL); - rtc_time_to_tm(now, tm); - - return 0; -} - -static int at32_rtc_settime(struct device *dev, struct rtc_time *tm) -{ - struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); - unsigned long now; - int ret; - - ret = rtc_tm_to_time(tm, &now); - if (ret == 0) - rtc_writel(rtc, VAL, now); - - return ret; -} - -static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); - - spin_lock_irq(&rtc->lock); - rtc_time_to_tm(rtc->alarm_time, &alrm->time); - alrm->enabled = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0; - alrm->pending = rtc_readl(rtc, ISR) & RTC_BIT(ISR_TOPI) ? 1 : 0; - spin_unlock_irq(&rtc->lock); - - return 0; -} - -static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); - unsigned long rtc_unix_time; - unsigned long alarm_unix_time; - int ret; - - rtc_unix_time = rtc_readl(rtc, VAL); - - ret = rtc_tm_to_time(&alrm->time, &alarm_unix_time); - if (ret) - return ret; - - if (alarm_unix_time < rtc_unix_time) - return -EINVAL; - - spin_lock_irq(&rtc->lock); - rtc->alarm_time = alarm_unix_time; - rtc_writel(rtc, TOP, rtc->alarm_time); - if (alrm->enabled) - rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) - | RTC_BIT(CTRL_TOPEN)); - else - rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) - & ~RTC_BIT(CTRL_TOPEN)); - spin_unlock_irq(&rtc->lock); - - return ret; -} - -static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); - int ret = 0; - - spin_lock_irq(&rtc->lock); - - if (enabled) { - if (rtc_readl(rtc, VAL) > rtc->alarm_time) { - ret = -EINVAL; - goto out; - } - rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) - | RTC_BIT(CTRL_TOPEN)); - rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); - rtc_writel(rtc, IER, RTC_BIT(IER_TOPI)); - } else { - rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) - & ~RTC_BIT(CTRL_TOPEN)); - rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); - rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); - } -out: - spin_unlock_irq(&rtc->lock); - - return ret; -} - -static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id) -{ - struct rtc_at32ap700x *rtc = (struct rtc_at32ap700x *)dev_id; - unsigned long isr = rtc_readl(rtc, ISR); - unsigned long events = 0; - int ret = IRQ_NONE; - - spin_lock(&rtc->lock); - - if (isr & RTC_BIT(ISR_TOPI)) { - rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); - rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); - rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) - & ~RTC_BIT(CTRL_TOPEN)); - rtc_writel(rtc, VAL, rtc->alarm_time); - events = RTC_AF | RTC_IRQF; - rtc_update_irq(rtc->rtc, 1, events); - ret = IRQ_HANDLED; - } - - spin_unlock(&rtc->lock); - - return ret; -} - -static const struct rtc_class_ops at32_rtc_ops = { - .read_time = at32_rtc_readtime, - .set_time = at32_rtc_settime, - .read_alarm = at32_rtc_readalarm, - .set_alarm = at32_rtc_setalarm, - .alarm_irq_enable = at32_rtc_alarm_irq_enable, -}; - -static int __init at32_rtc_probe(struct platform_device *pdev) -{ - struct resource *regs; - struct rtc_at32ap700x *rtc; - int irq; - int ret; - - rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x), - GFP_KERNEL); - if (!rtc) - return -ENOMEM; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) { - dev_dbg(&pdev->dev, "no mmio resource defined\n"); - return -ENXIO; - } - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_dbg(&pdev->dev, "could not get irq\n"); - return -ENXIO; - } - - rtc->irq = irq; - rtc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); - if (!rtc->regs) { - dev_dbg(&pdev->dev, "could not map I/O memory\n"); - return -ENOMEM; - } - spin_lock_init(&rtc->lock); - - /* - * Maybe init RTC: count from zero at 1 Hz, disable wrap irq. - * - * Do not reset VAL register, as it can hold an old time - * from last JTAG reset. - */ - if (!(rtc_readl(rtc, CTRL) & RTC_BIT(CTRL_EN))) { - rtc_writel(rtc, CTRL, RTC_BIT(CTRL_PCLR)); - rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); - rtc_writel(rtc, CTRL, RTC_BF(CTRL_PSEL, 0xe) - | RTC_BIT(CTRL_EN)); - } - - ret = devm_request_irq(&pdev->dev, irq, at32_rtc_interrupt, IRQF_SHARED, - "rtc", rtc); - if (ret) { - dev_dbg(&pdev->dev, "could not request irq %d\n", irq); - return ret; - } - - platform_set_drvdata(pdev, rtc); - - rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &at32_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc)) { - dev_dbg(&pdev->dev, "could not register rtc device\n"); - return PTR_ERR(rtc->rtc); - } - - device_init_wakeup(&pdev->dev, 1); - - dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", - (unsigned long)rtc->regs, rtc->irq); - - return 0; -} - -static int __exit at32_rtc_remove(struct platform_device *pdev) -{ - device_init_wakeup(&pdev->dev, 0); - - return 0; -} - -MODULE_ALIAS("platform:at32ap700x_rtc"); - -static struct platform_driver at32_rtc_driver = { - .remove = __exit_p(at32_rtc_remove), - .driver = { - .name = "at32ap700x_rtc", - }, -}; - -module_platform_driver_probe(at32_rtc_driver, at32_rtc_probe); - -MODULE_AUTHOR("Hans-Christian Egtvedt "); -MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x"); -MODULE_LICENSE("GPL"); -- cgit From b1db551324f72fa14ad82ca31237a7ed418104df Mon Sep 17 00:00:00 2001 From: Christophe Lombard Date: Thu, 11 Jan 2018 09:55:25 +0100 Subject: cxl: Add support for ASB_Notify on POWER9 The POWER9 core supports a new feature: ASB_Notify which requires the support of the Special Purpose Register: TIDR. The ASB_Notify command, generated by the AFU, will attempt to wake-up the host thread identified by the particular LPID:PID:TID. This patch assign a unique TIDR (thread id) for the current thread which will be used in the process element entry. Signed-off-by: Christophe Lombard Reviewed-by: Philippe Bergheaud Acked-by: Frederic Barrat Reviewed-by: Vaibhav Jain Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/context.c | 2 ++ drivers/misc/cxl/cxl.h | 3 +++ drivers/misc/cxl/cxllib.c | 3 ++- drivers/misc/cxl/file.c | 15 +++++++++++++-- drivers/misc/cxl/native.c | 13 ++++++++++++- 5 files changed, 32 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 12a41b2753f0..7ff315ad3692 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -45,6 +45,8 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) ctx->pid = NULL; /* Set in start work ioctl */ mutex_init(&ctx->mapping_lock); ctx->mapping = NULL; + ctx->tidr = 0; + ctx->assign_tidr = false; if (cxl_is_power8()) { spin_lock_init(&ctx->sste_lock); diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index e46a4062904a..53149fbd780e 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -630,6 +630,9 @@ struct cxl_context { struct list_head extra_irq_contexts; struct mm_struct *mm; + + u16 tidr; + bool assign_tidr; }; struct cxl_irq_info; diff --git a/drivers/misc/cxl/cxllib.c b/drivers/misc/cxl/cxllib.c index dc9bc1807fdf..30ccba436b3b 100644 --- a/drivers/misc/cxl/cxllib.c +++ b/drivers/misc/cxl/cxllib.c @@ -199,10 +199,11 @@ int cxllib_get_PE_attributes(struct task_struct *task, */ attr->pid = mm->context.id; mmput(mm); + attr->tid = task->thread.tidr; } else { attr->pid = 0; + attr->tid = 0; } - attr->tid = 0; return 0; } EXPORT_SYMBOL_GPL(cxllib_get_PE_attributes); diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 76c0b0ca9388..93fd381f6484 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -173,7 +173,7 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, * flags are set it's invalid */ if (work.reserved1 || work.reserved2 || work.reserved3 || - work.reserved4 || work.reserved5 || work.reserved6 || + work.reserved4 || work.reserved5 || (work.flags & ~CXL_START_WORK_ALL)) { rc = -EINVAL; goto out; @@ -186,12 +186,16 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, rc = -EINVAL; goto out; } + if ((rc = afu_register_irqs(ctx, work.num_interrupts))) goto out; if (work.flags & CXL_START_WORK_AMR) amr = work.amr & mfspr(SPRN_UAMOR); + if (work.flags & CXL_START_WORK_TID) + ctx->assign_tidr = true; + ctx->mmio_err_ff = !!(work.flags & CXL_START_WORK_ERR_FF); /* @@ -263,8 +267,15 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, goto out; } - ctx->status = STARTED; rc = 0; + if (work.flags & CXL_START_WORK_TID) { + work.tid = ctx->tidr; + if (copy_to_user(uwork, &work, sizeof(work))) + rc = -EFAULT; + } + + ctx->status = STARTED; + out: mutex_unlock(&ctx->status_mutex); return rc; diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 02b6b45b4c20..1b3d7c65ea3f 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "cxl.h" @@ -655,6 +656,7 @@ static void update_ivtes_directed(struct cxl_context *ctx) static int process_element_entry_psl9(struct cxl_context *ctx, u64 wed, u64 amr) { u32 pid; + int rc; cxl_assign_psn_space(ctx); @@ -673,7 +675,16 @@ static int process_element_entry_psl9(struct cxl_context *ctx, u64 wed, u64 amr) pid = ctx->mm->context.id; } - ctx->elem->common.tid = 0; + /* Assign a unique TIDR (thread id) for the current thread */ + if (!(ctx->tidr) && (ctx->assign_tidr)) { + rc = set_thread_tidr(current); + if (rc) + return -ENODEV; + ctx->tidr = current->thread.tidr; + pr_devel("%s: current tidr: %d\n", __func__, ctx->tidr); + } + + ctx->elem->common.tid = cpu_to_be32(ctx->tidr); ctx->elem->common.pid = cpu_to_be32(pid); ctx->elem->sr = cpu_to_be64(calculate_sr(ctx)); -- cgit From 2fcf3ae508c23bea25ab0a0e639805eb7e573b58 Mon Sep 17 00:00:00 2001 From: Michael Bringmann Date: Fri, 1 Dec 2017 17:19:48 -0600 Subject: hotplug/drc-info: Add code to search ibm,drc-info property rpadlpar_core.c: Provide parallel routines to search the older device- tree properties ("ibm,drc-indexes", "ibm,drc-names", "ibm,drc-types" and "ibm,drc-power-domains"), or the new property "ibm,drc-info". The interface to examine the DRC information is changed from a "get" function that returns values for local verification elsewhere, to a "check" function that validates the 'name' and/or 'type' of a device node. This update hides the format of the underlying device-tree properties, and concentrates the value checks into a single function without requiring the user to verify whether a search was successful. Signed-off-by: Michael Bringmann Signed-off-by: Michael Ellerman --- drivers/pci/hotplug/rpadlpar_core.c | 13 ++--- drivers/pci/hotplug/rpadlpar_sysfs.c | 3 +- drivers/pci/hotplug/rpaphp.h | 8 ++- drivers/pci/hotplug/rpaphp_core.c | 107 +++++++++++++++++++++++++++-------- 4 files changed, 94 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index a3449d717a99..fc01d7d807f3 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "../pci.h" #include "rpaphp.h" @@ -44,15 +45,14 @@ static struct device_node *find_vio_slot_node(char *drc_name) { struct device_node *parent = of_find_node_by_name(NULL, "vdevice"); struct device_node *dn = NULL; - char *name; int rc; if (!parent) return NULL; while ((dn = of_get_next_child(parent, dn))) { - rc = rpaphp_get_drc_props(dn, NULL, &name, NULL, NULL); - if ((rc == 0) && (!strcmp(drc_name, name))) + rc = rpaphp_check_drc_props(dn, drc_name, NULL); + if (rc == 0) break; } @@ -64,15 +64,12 @@ static struct device_node *find_php_slot_pci_node(char *drc_name, char *drc_type) { struct device_node *np = NULL; - char *name; - char *type; int rc; while ((np = of_find_node_by_name(np, "pci"))) { - rc = rpaphp_get_drc_props(np, NULL, &name, &type, NULL); + rc = rpaphp_check_drc_props(np, drc_name, drc_type); if (rc == 0) - if (!strcmp(drc_name, name) && !strcmp(drc_type, type)) - break; + break; } return np; diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index edb5d8a53020..b806314349cf 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -16,6 +16,7 @@ #include #include #include +#include "rpaphp.h" #include "rpadlpar.h" #include "../pci.h" @@ -27,8 +28,6 @@ #define ADD_SLOT_ATTR_NAME add_slot #define REMOVE_SLOT_ATTR_NAME remove_slot -#define MAX_DRC_NAME_LEN 64 - static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t nbytes) { diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 7db024e68fe6..bdb844b01a3d 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -64,6 +64,10 @@ extern bool rpaphp_debug; #define CONFIGURED 1 #define EMPTY 0 +/* DRC constants */ + +#define MAX_DRC_NAME_LEN 64 + /* * struct slot - slot information for each *physical* slot */ @@ -91,8 +95,8 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state); /* rpaphp_core.c */ int rpaphp_add_slot(struct device_node *dn); -int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, - char **drc_name, char **drc_type, int *drc_power_domain); +int rpaphp_check_drc_props(struct device_node *dn, char *drc_name, + char *drc_type); /* rpaphp_slot.c */ void dealloc_slot_struct(struct slot *slot); diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 1e29abaaea08..53902c7c38f2 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include /* for eeh_add_device() */ #include /* rtas_call */ #include /* for pci_controller */ @@ -196,25 +197,21 @@ static int get_children_props(struct device_node *dn, const int **drc_indexes, return 0; } -/* To get the DRC props describing the current node, first obtain it's - * my-drc-index property. Next obtain the DRC list from it's parent. Use - * the my-drc-index for correlation, and obtain the requested properties. + +/* Verify the existence of 'drc_name' and/or 'drc_type' within the + * current node. First obtain it's my-drc-index property. Next, + * obtain the DRC info from it's parent. Use the my-drc-index for + * correlation, and obtain/validate the requested properties. */ -int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, - char **drc_name, char **drc_type, int *drc_power_domain) + +static int rpaphp_check_drc_props_v1(struct device_node *dn, char *drc_name, + char *drc_type, unsigned int my_index) { + char *name_tmp, *type_tmp; const int *indexes, *names; const int *types, *domains; - const unsigned int *my_index; - char *name_tmp, *type_tmp; int i, rc; - my_index = of_get_property(dn, "ibm,my-drc-index", NULL); - if (!my_index) { - /* Node isn't DLPAR/hotplug capable */ - return -EINVAL; - } - rc = get_children_props(dn->parent, &indexes, &names, &types, &domains); if (rc < 0) { return -EINVAL; @@ -225,24 +222,84 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, /* Iterate through parent properties, looking for my-drc-index */ for (i = 0; i < be32_to_cpu(indexes[0]); i++) { - if ((unsigned int) indexes[i + 1] == *my_index) { - if (drc_name) - *drc_name = name_tmp; - if (drc_type) - *drc_type = type_tmp; - if (drc_index) - *drc_index = be32_to_cpu(*my_index); - if (drc_power_domain) - *drc_power_domain = be32_to_cpu(domains[i+1]); - return 0; - } + if ((unsigned int) indexes[i + 1] == my_index) + break; + name_tmp += (strlen(name_tmp) + 1); type_tmp += (strlen(type_tmp) + 1); } + if (((drc_name == NULL) || (drc_name && !strcmp(drc_name, name_tmp))) && + ((drc_type == NULL) || (drc_type && !strcmp(drc_type, type_tmp)))) + return 0; + return -EINVAL; } -EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); + +static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name, + char *drc_type, unsigned int my_index) +{ + struct property *info; + unsigned int entries; + struct of_drc_info drc; + const __be32 *value; + char cell_drc_name[MAX_DRC_NAME_LEN]; + int j, fndit; + + info = of_find_property(dn->parent, "ibm,drc-info", NULL); + if (info == NULL) + return -EINVAL; + + value = of_prop_next_u32(info, NULL, &entries); + if (!value) + return -EINVAL; + + for (j = 0; j < entries; j++) { + of_read_drc_info_cell(&info, &value, &drc); + + /* Should now know end of current entry */ + + if (my_index > drc.last_drc_index) + continue; + + fndit = 1; + break; + } + /* Found it */ + + if (fndit) + sprintf(cell_drc_name, "%s%d", drc.drc_name_prefix, + my_index); + + if (((drc_name == NULL) || + (drc_name && !strcmp(drc_name, cell_drc_name))) && + ((drc_type == NULL) || + (drc_type && !strcmp(drc_type, drc.drc_type)))) + return 0; + + return -EINVAL; +} + +int rpaphp_check_drc_props(struct device_node *dn, char *drc_name, + char *drc_type) +{ + const unsigned int *my_index; + + my_index = of_get_property(dn, "ibm,my-drc-index", NULL); + if (!my_index) { + /* Node isn't DLPAR/hotplug capable */ + return -EINVAL; + } + + if (firmware_has_feature(FW_FEATURE_DRC_INFO)) + return rpaphp_check_drc_props_v2(dn, drc_name, drc_type, + *my_index); + else + return rpaphp_check_drc_props_v1(dn, drc_name, drc_type, + *my_index); +} +EXPORT_SYMBOL_GPL(rpaphp_check_drc_props); + static int is_php_type(char *drc_type) { -- cgit From 00f7b29f6e9b8ab900b1de19e72c457fd6702ccb Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Tue, 26 Dec 2017 15:12:41 +0100 Subject: backlight: Fix old-style function definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning: drivers/macintosh/via-pmu-backlight.c: In function ‘pmu_backlight_init’: drivers/macintosh/via-pmu-backlight.c:140:13: warning: old-style function definition [-Wold-style-definition] void __init pmu_backlight_init() ^~~~~~~~~~~~~~~~~~ Signed-off-by: Mathieu Malaterre Acked-by: Daniel Thompson Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu-backlight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index 89ed51571b62..50ada02ae75d 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -137,7 +137,7 @@ void pmu_backlight_set_sleep(int sleep) } #endif /* CONFIG_PM */ -void __init pmu_backlight_init() +void __init pmu_backlight_init(void) { struct backlight_properties props; struct backlight_device *bd; -- cgit From ff5fdafc9e9702846480e0cea55ba861f72140a2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 19 Jan 2018 18:17:46 +0100 Subject: ARM: 8745/1: get rid of __memzero() The __memzero assembly code is almost identical to memset's except for two orr instructions. The runtime performance of __memset(p, n) and memset(p, 0, n) is accordingly almost identical. However, the memset() macro used to guard against a zero length and to call __memzero at compile time when the fill value is a constant zero interferes with compiler optimizations. Arnd found tha the test against a zero length brings up some new warnings with gcc v8: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82103 And successively rremoving the test against a zero length and the call to __memzero optimization produces the following kernel sizes for defconfig with gcc 6: text data bss dec hex filename 12248142 6278960 413588 18940690 1210312 vmlinux.orig 12244474 6278960 413588 18937022 120f4be vmlinux.no_zero_test 12239160 6278960 413588 18931708 120dffc vmlinux.no_memzero So it is probably not worth keeping __memzero around given that the compiler can do a better job at inlining trivial memset(p,0,n) on its own. And the memset code already handles a zero length just fine. Suggested-by: Arnd Bergmann Signed-off-by: Nicolas Pitre Acked-by: Ard Biesheuvel Acked-by: Arnd Bergmann Signed-off-by: Russell King --- drivers/dma/imx-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 331f863c605e..715b39ae5a46 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -765,7 +765,7 @@ static int imxdma_alloc_chan_resources(struct dma_chan *chan) desc = kzalloc(sizeof(*desc), GFP_KERNEL); if (!desc) break; - __memzero(&desc->desc, sizeof(struct dma_async_tx_descriptor)); + memset(&desc->desc, 0, sizeof(struct dma_async_tx_descriptor)); dma_async_tx_descriptor_init(&desc->desc, chan); desc->desc.tx_submit = imxdma_tx_submit; /* txd.flags will be overwritten in prep funcs */ -- cgit From f90160fc956da4caf5e784a850b65a5adf0319d9 Mon Sep 17 00:00:00 2001 From: Alexandre Torgue Date: Mon, 11 Dec 2017 09:54:32 +0100 Subject: pinctrl: stm32: add STM32F769 MCU support This patch which adds STM32F769 pinctrl and GPIO support, relies on the generic STM32 pinctrl driver. Signed-off-by: Alexandre Torgue Acked-by: Patrice CHOTARD Signed-off-by: Linus Walleij --- drivers/pinctrl/stm32/Kconfig | 6 + drivers/pinctrl/stm32/Makefile | 1 + drivers/pinctrl/stm32/pinctrl-stm32f769.c | 1827 +++++++++++++++++++++++++++++ 3 files changed, 1834 insertions(+) create mode 100644 drivers/pinctrl/stm32/pinctrl-stm32f769.c (limited to 'drivers') diff --git a/drivers/pinctrl/stm32/Kconfig b/drivers/pinctrl/stm32/Kconfig index a6d045d5f156..1c4e00b2eb65 100644 --- a/drivers/pinctrl/stm32/Kconfig +++ b/drivers/pinctrl/stm32/Kconfig @@ -27,6 +27,12 @@ config PINCTRL_STM32F746 default MACH_STM32F746 select PINCTRL_STM32 +config PINCTRL_STM32F769 + bool "STMicroelectronics STM32F769 pin control" if COMPILE_TEST && !MACH_STM32F769 + depends on OF + default MACH_STM32F769 + select PINCTRL_STM32 + config PINCTRL_STM32H743 bool "STMicroelectronics STM32H743 pin control" if COMPILE_TEST && !MACH_STM32H743 depends on OF diff --git a/drivers/pinctrl/stm32/Makefile b/drivers/pinctrl/stm32/Makefile index b52223d6810c..f7c56d4b941c 100644 --- a/drivers/pinctrl/stm32/Makefile +++ b/drivers/pinctrl/stm32/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o obj-$(CONFIG_PINCTRL_STM32F429) += pinctrl-stm32f429.o obj-$(CONFIG_PINCTRL_STM32F469) += pinctrl-stm32f469.o obj-$(CONFIG_PINCTRL_STM32F746) += pinctrl-stm32f746.o +obj-$(CONFIG_PINCTRL_STM32F769) += pinctrl-stm32f769.o obj-$(CONFIG_PINCTRL_STM32H743) += pinctrl-stm32h743.o obj-$(CONFIG_PINCTRL_STM32MP157) += pinctrl-stm32mp157.o diff --git a/drivers/pinctrl/stm32/pinctrl-stm32f769.c b/drivers/pinctrl/stm32/pinctrl-stm32f769.c new file mode 100644 index 000000000000..f81c51c5aedf --- /dev/null +++ b/drivers/pinctrl/stm32/pinctrl-stm32f769.c @@ -0,0 +1,1827 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2017 + * Author: Alexandre Torgue for STMicroelectronics. + */ +#include +#include +#include + +#include "pinctrl-stm32.h" + +static const struct stm32_desc_pin stm32f769_pins[] = { + STM32_PIN( + PINCTRL_PIN(0, "PA0"), + STM32_FUNCTION(0, "GPIOA0"), + STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), + STM32_FUNCTION(3, "TIM5_CH1"), + STM32_FUNCTION(4, "TIM8_ETR"), + STM32_FUNCTION(8, "USART2_CTS"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(12, "ETH_MII_CRS"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(1, "PA1"), + STM32_FUNCTION(0, "GPIOA1"), + STM32_FUNCTION(2, "TIM2_CH2"), + STM32_FUNCTION(3, "TIM5_CH2"), + STM32_FUNCTION(8, "USART2_RTS"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO3"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(12, "ETH_MII_RX_CLK ETH_RMII_REF_CLK"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(2, "PA2"), + STM32_FUNCTION(0, "GPIOA2"), + STM32_FUNCTION(2, "TIM2_CH3"), + STM32_FUNCTION(3, "TIM5_CH3"), + STM32_FUNCTION(4, "TIM9_CH1"), + STM32_FUNCTION(8, "USART2_TX"), + STM32_FUNCTION(9, "SAI2_SCK_B"), + STM32_FUNCTION(12, "ETH_MDIO"), + STM32_FUNCTION(13, "MDIOS_MDIO"), + STM32_FUNCTION(15, "LCD_R1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(3, "PA3"), + STM32_FUNCTION(0, "GPIOA3"), + STM32_FUNCTION(2, "TIM2_CH4"), + STM32_FUNCTION(3, "TIM5_CH4"), + STM32_FUNCTION(4, "TIM9_CH2"), + STM32_FUNCTION(8, "USART2_RX"), + STM32_FUNCTION(10, "LCD_B2"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D0"), + STM32_FUNCTION(12, "ETH_MII_COL"), + STM32_FUNCTION(15, "LCD_B5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(4, "PA4"), + STM32_FUNCTION(0, "GPIOA4"), + STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), + STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"), + STM32_FUNCTION(8, "USART2_CK"), + STM32_FUNCTION(9, "SPI6_NSS"), + STM32_FUNCTION(13, "OTG_HS_SOF"), + STM32_FUNCTION(14, "DCMI_HSYNC"), + STM32_FUNCTION(15, "LCD_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(5, "PA5"), + STM32_FUNCTION(0, "GPIOA5"), + STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), + STM32_FUNCTION(4, "TIM8_CH1N"), + STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"), + STM32_FUNCTION(9, "SPI6_SCK"), + STM32_FUNCTION(11, "OTG_HS_ULPI_CK"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(6, "PA6"), + STM32_FUNCTION(0, "GPIOA6"), + STM32_FUNCTION(2, "TIM1_BKIN"), + STM32_FUNCTION(3, "TIM3_CH1"), + STM32_FUNCTION(4, "TIM8_BKIN"), + STM32_FUNCTION(6, "SPI1_MISO"), + STM32_FUNCTION(9, "SPI6_MISO"), + STM32_FUNCTION(10, "TIM13_CH1"), + STM32_FUNCTION(13, "MDIOS_MDC"), + STM32_FUNCTION(14, "DCMI_PIXCLK"), + STM32_FUNCTION(15, "LCD_G2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(7, "PA7"), + STM32_FUNCTION(0, "GPIOA7"), + STM32_FUNCTION(2, "TIM1_CH1N"), + STM32_FUNCTION(3, "TIM3_CH2"), + STM32_FUNCTION(4, "TIM8_CH1N"), + STM32_FUNCTION(6, "SPI1_MOSI I2S1_SD"), + STM32_FUNCTION(9, "SPI6_MOSI"), + STM32_FUNCTION(10, "TIM14_CH1"), + STM32_FUNCTION(12, "ETH_MII_RX_DV ETH_RMII_CRS_DV"), + STM32_FUNCTION(13, "FMC_SDNWE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(8, "PA8"), + STM32_FUNCTION(0, "GPIOA8"), + STM32_FUNCTION(1, "MCO1"), + STM32_FUNCTION(2, "TIM1_CH1"), + STM32_FUNCTION(4, "TIM8_BKIN2"), + STM32_FUNCTION(5, "I2C3_SCL"), + STM32_FUNCTION(8, "USART1_CK"), + STM32_FUNCTION(11, "OTG_FS_SOF"), + STM32_FUNCTION(12, "CAN3_RX"), + STM32_FUNCTION(13, "UART7_RX"), + STM32_FUNCTION(14, "LCD_B3"), + STM32_FUNCTION(15, "LCD_R6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(9, "PA9"), + STM32_FUNCTION(0, "GPIOA9"), + STM32_FUNCTION(2, "TIM1_CH2"), + STM32_FUNCTION(5, "I2C3_SMBA"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(8, "USART1_TX"), + STM32_FUNCTION(14, "DCMI_D0"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(10, "PA10"), + STM32_FUNCTION(0, "GPIOA10"), + STM32_FUNCTION(2, "TIM1_CH3"), + STM32_FUNCTION(8, "USART1_RX"), + STM32_FUNCTION(10, "LCD_B4"), + STM32_FUNCTION(11, "OTG_FS_ID"), + STM32_FUNCTION(13, "MDIOS_MDIO"), + STM32_FUNCTION(14, "DCMI_D1"), + STM32_FUNCTION(15, "LCD_B1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(11, "PA11"), + STM32_FUNCTION(0, "GPIOA11"), + STM32_FUNCTION(2, "TIM1_CH4"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(7, "UART4_RX"), + STM32_FUNCTION(8, "USART1_CTS"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(11, "OTG_FS_DM"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(12, "PA12"), + STM32_FUNCTION(0, "GPIOA12"), + STM32_FUNCTION(2, "TIM1_ETR"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "UART4_TX"), + STM32_FUNCTION(8, "USART1_RTS"), + STM32_FUNCTION(9, "SAI2_FS_B"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(11, "OTG_FS_DP"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(13, "PA13"), + STM32_FUNCTION(0, "GPIOA13"), + STM32_FUNCTION(1, "JTMS SWDIO"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(14, "PA14"), + STM32_FUNCTION(0, "GPIOA14"), + STM32_FUNCTION(1, "JTCK SWCLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(15, "PA15"), + STM32_FUNCTION(0, "GPIOA15"), + STM32_FUNCTION(1, "JTDI"), + STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), + STM32_FUNCTION(5, "HDMI_CEC"), + STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), + STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"), + STM32_FUNCTION(8, "SPI6_NSS"), + STM32_FUNCTION(9, "UART4_RTS"), + STM32_FUNCTION(12, "CAN3_TX"), + STM32_FUNCTION(13, "UART7_TX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(16, "PB0"), + STM32_FUNCTION(0, "GPIOB0"), + STM32_FUNCTION(2, "TIM1_CH2N"), + STM32_FUNCTION(3, "TIM3_CH3"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(7, "DFSDM_CKOUT"), + STM32_FUNCTION(9, "UART4_CTS"), + STM32_FUNCTION(10, "LCD_R3"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D1"), + STM32_FUNCTION(12, "ETH_MII_RXD2"), + STM32_FUNCTION(15, "LCD_G1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(17, "PB1"), + STM32_FUNCTION(0, "GPIOB1"), + STM32_FUNCTION(2, "TIM1_CH3N"), + STM32_FUNCTION(3, "TIM3_CH4"), + STM32_FUNCTION(4, "TIM8_CH3N"), + STM32_FUNCTION(7, "DFSDM_DATIN1"), + STM32_FUNCTION(10, "LCD_R6"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D2"), + STM32_FUNCTION(12, "ETH_MII_RXD3"), + STM32_FUNCTION(15, "LCD_G0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(18, "PB2"), + STM32_FUNCTION(0, "GPIOB2"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(8, "SPI3_MOSI I2S3_SD"), + STM32_FUNCTION(10, "QUADSPI_CLK"), + STM32_FUNCTION(11, "DFSDM_CKIN1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(19, "PB3"), + STM32_FUNCTION(0, "GPIOB3"), + STM32_FUNCTION(1, "JTDO TRACESWO"), + STM32_FUNCTION(2, "TIM2_CH2"), + STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"), + STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"), + STM32_FUNCTION(9, "SPI6_SCK"), + STM32_FUNCTION(11, "SDMMC2_D2"), + STM32_FUNCTION(12, "CAN3_RX"), + STM32_FUNCTION(13, "UART7_RX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(20, "PB4"), + STM32_FUNCTION(0, "GPIOB4"), + STM32_FUNCTION(1, "NJTRST"), + STM32_FUNCTION(3, "TIM3_CH1"), + STM32_FUNCTION(6, "SPI1_MISO"), + STM32_FUNCTION(7, "SPI3_MISO"), + STM32_FUNCTION(8, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(9, "SPI6_MISO"), + STM32_FUNCTION(11, "SDMMC2_D3"), + STM32_FUNCTION(12, "CAN3_TX"), + STM32_FUNCTION(13, "UART7_TX"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(21, "PB5"), + STM32_FUNCTION(0, "GPIOB5"), + STM32_FUNCTION(2, "UART5_RX"), + STM32_FUNCTION(3, "TIM3_CH2"), + STM32_FUNCTION(5, "I2C1_SMBA"), + STM32_FUNCTION(6, "SPI1_MOSI I2S1_SD"), + STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"), + STM32_FUNCTION(9, "SPI6_MOSI"), + STM32_FUNCTION(10, "CAN2_RX"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D7"), + STM32_FUNCTION(12, "ETH_PPS_OUT"), + STM32_FUNCTION(13, "FMC_SDCKE1"), + STM32_FUNCTION(14, "DCMI_D10"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(22, "PB6"), + STM32_FUNCTION(0, "GPIOB6"), + STM32_FUNCTION(2, "UART5_TX"), + STM32_FUNCTION(3, "TIM4_CH1"), + STM32_FUNCTION(4, "HDMI_CEC"), + STM32_FUNCTION(5, "I2C1_SCL"), + STM32_FUNCTION(7, "DFSDM_DATIN5"), + STM32_FUNCTION(8, "USART1_TX"), + STM32_FUNCTION(10, "CAN2_TX"), + STM32_FUNCTION(11, "QUADSPI_BK1_NCS"), + STM32_FUNCTION(12, "I2C4_SCL"), + STM32_FUNCTION(13, "FMC_SDNE1"), + STM32_FUNCTION(14, "DCMI_D5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(23, "PB7"), + STM32_FUNCTION(0, "GPIOB7"), + STM32_FUNCTION(3, "TIM4_CH2"), + STM32_FUNCTION(5, "I2C1_SDA"), + STM32_FUNCTION(7, "DFSDM_CKIN5"), + STM32_FUNCTION(8, "USART1_RX"), + STM32_FUNCTION(12, "I2C4_SDA"), + STM32_FUNCTION(13, "FMC_NL"), + STM32_FUNCTION(14, "DCMI_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(24, "PB8"), + STM32_FUNCTION(0, "GPIOB8"), + STM32_FUNCTION(2, "I2C4_SCL"), + STM32_FUNCTION(3, "TIM4_CH3"), + STM32_FUNCTION(4, "TIM10_CH1"), + STM32_FUNCTION(5, "I2C1_SCL"), + STM32_FUNCTION(7, "DFSDM_CKIN7"), + STM32_FUNCTION(8, "UART5_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(11, "SDMMC2_D4"), + STM32_FUNCTION(12, "ETH_MII_TXD3"), + STM32_FUNCTION(13, "SDMMC1_D4"), + STM32_FUNCTION(14, "DCMI_D6"), + STM32_FUNCTION(15, "LCD_B6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(25, "PB9"), + STM32_FUNCTION(0, "GPIOB9"), + STM32_FUNCTION(2, "I2C4_SDA"), + STM32_FUNCTION(3, "TIM4_CH4"), + STM32_FUNCTION(4, "TIM11_CH1"), + STM32_FUNCTION(5, "I2C1_SDA"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(7, "DFSDM_DATIN7"), + STM32_FUNCTION(8, "UART5_TX"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(11, "SDMMC2_D5"), + STM32_FUNCTION(12, "I2C4_SMBA"), + STM32_FUNCTION(13, "SDMMC1_D5"), + STM32_FUNCTION(14, "DCMI_D7"), + STM32_FUNCTION(15, "LCD_B7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(26, "PB10"), + STM32_FUNCTION(0, "GPIOB10"), + STM32_FUNCTION(2, "TIM2_CH3"), + STM32_FUNCTION(5, "I2C2_SCL"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "DFSDM_DATIN7"), + STM32_FUNCTION(8, "USART3_TX"), + STM32_FUNCTION(10, "QUADSPI_BK1_NCS"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D3"), + STM32_FUNCTION(12, "ETH_MII_RX_ER"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(27, "PB11"), + STM32_FUNCTION(0, "GPIOB11"), + STM32_FUNCTION(2, "TIM2_CH4"), + STM32_FUNCTION(5, "I2C2_SDA"), + STM32_FUNCTION(7, "DFSDM_CKIN7"), + STM32_FUNCTION(8, "USART3_RX"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D4"), + STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"), + STM32_FUNCTION(14, "DSI_TE"), + STM32_FUNCTION(15, "LCD_G5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(28, "PB12"), + STM32_FUNCTION(0, "GPIOB12"), + STM32_FUNCTION(2, "TIM1_BKIN"), + STM32_FUNCTION(5, "I2C2_SMBA"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(7, "DFSDM_DATIN1"), + STM32_FUNCTION(8, "USART3_CK"), + STM32_FUNCTION(9, "UART5_RX"), + STM32_FUNCTION(10, "CAN2_RX"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D5"), + STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"), + STM32_FUNCTION(13, "OTG_HS_ID"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(29, "PB13"), + STM32_FUNCTION(0, "GPIOB13"), + STM32_FUNCTION(2, "TIM1_CH1N"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "DFSDM_CKIN1"), + STM32_FUNCTION(8, "USART3_CTS"), + STM32_FUNCTION(9, "UART5_TX"), + STM32_FUNCTION(10, "CAN2_TX"), + STM32_FUNCTION(11, "OTG_HS_ULPI_D6"), + STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(30, "PB14"), + STM32_FUNCTION(0, "GPIOB14"), + STM32_FUNCTION(2, "TIM1_CH2N"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(5, "USART1_TX"), + STM32_FUNCTION(6, "SPI2_MISO"), + STM32_FUNCTION(7, "DFSDM_DATIN2"), + STM32_FUNCTION(8, "USART3_RTS"), + STM32_FUNCTION(9, "UART4_RTS"), + STM32_FUNCTION(10, "TIM12_CH1"), + STM32_FUNCTION(11, "SDMMC2_D0"), + STM32_FUNCTION(13, "OTG_HS_DM"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(31, "PB15"), + STM32_FUNCTION(0, "GPIOB15"), + STM32_FUNCTION(1, "RTC_REFIN"), + STM32_FUNCTION(2, "TIM1_CH3N"), + STM32_FUNCTION(4, "TIM8_CH3N"), + STM32_FUNCTION(5, "USART1_RX"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"), + STM32_FUNCTION(7, "DFSDM_CKIN2"), + STM32_FUNCTION(9, "UART4_CTS"), + STM32_FUNCTION(10, "TIM12_CH2"), + STM32_FUNCTION(11, "SDMMC2_D1"), + STM32_FUNCTION(13, "OTG_HS_DP"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(32, "PC0"), + STM32_FUNCTION(0, "GPIOC0"), + STM32_FUNCTION(4, "DFSDM_CKIN0"), + STM32_FUNCTION(7, "DFSDM_DATIN4"), + STM32_FUNCTION(9, "SAI2_FS_B"), + STM32_FUNCTION(11, "OTG_HS_ULPI_STP"), + STM32_FUNCTION(13, "FMC_SDNWE"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(33, "PC1"), + STM32_FUNCTION(0, "GPIOC1"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(4, "DFSDM_DATIN0"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(11, "DFSDM_CKIN4"), + STM32_FUNCTION(12, "ETH_MDC"), + STM32_FUNCTION(13, "MDIOS_MDC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(34, "PC2"), + STM32_FUNCTION(0, "GPIOC2"), + STM32_FUNCTION(4, "DFSDM_CKIN1"), + STM32_FUNCTION(6, "SPI2_MISO"), + STM32_FUNCTION(7, "DFSDM_CKOUT"), + STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"), + STM32_FUNCTION(12, "ETH_MII_TXD2"), + STM32_FUNCTION(13, "FMC_SDNE0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(35, "PC3"), + STM32_FUNCTION(0, "GPIOC3"), + STM32_FUNCTION(4, "DFSDM_DATIN1"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"), + STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"), + STM32_FUNCTION(12, "ETH_MII_TX_CLK"), + STM32_FUNCTION(13, "FMC_SDCKE0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(36, "PC4"), + STM32_FUNCTION(0, "GPIOC4"), + STM32_FUNCTION(4, "DFSDM_CKIN2"), + STM32_FUNCTION(6, "I2S1_MCK"), + STM32_FUNCTION(9, "SPDIF_RX2"), + STM32_FUNCTION(12, "ETH_MII_RXD0 ETH_RMII_RXD0"), + STM32_FUNCTION(13, "FMC_SDNE0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(37, "PC5"), + STM32_FUNCTION(0, "GPIOC5"), + STM32_FUNCTION(4, "DFSDM_DATIN2"), + STM32_FUNCTION(9, "SPDIF_RX3"), + STM32_FUNCTION(12, "ETH_MII_RXD1 ETH_RMII_RXD1"), + STM32_FUNCTION(13, "FMC_SDCKE0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(38, "PC6"), + STM32_FUNCTION(0, "GPIOC6"), + STM32_FUNCTION(3, "TIM3_CH1"), + STM32_FUNCTION(4, "TIM8_CH1"), + STM32_FUNCTION(6, "I2S2_MCK"), + STM32_FUNCTION(8, "DFSDM_CKIN3"), + STM32_FUNCTION(9, "USART6_TX"), + STM32_FUNCTION(10, "FMC_NWAIT"), + STM32_FUNCTION(11, "SDMMC2_D6"), + STM32_FUNCTION(13, "SDMMC1_D6"), + STM32_FUNCTION(14, "DCMI_D0"), + STM32_FUNCTION(15, "LCD_HSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(39, "PC7"), + STM32_FUNCTION(0, "GPIOC7"), + STM32_FUNCTION(3, "TIM3_CH2"), + STM32_FUNCTION(4, "TIM8_CH2"), + STM32_FUNCTION(7, "I2S3_MCK"), + STM32_FUNCTION(8, "DFSDM_DATIN3"), + STM32_FUNCTION(9, "USART6_RX"), + STM32_FUNCTION(10, "FMC_NE1"), + STM32_FUNCTION(11, "SDMMC2_D7"), + STM32_FUNCTION(13, "SDMMC1_D7"), + STM32_FUNCTION(14, "DCMI_D1"), + STM32_FUNCTION(15, "LCD_G6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(40, "PC8"), + STM32_FUNCTION(0, "GPIOC8"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(3, "TIM3_CH3"), + STM32_FUNCTION(4, "TIM8_CH3"), + STM32_FUNCTION(8, "UART5_RTS"), + STM32_FUNCTION(9, "USART6_CK"), + STM32_FUNCTION(10, "FMC_NE2 FMC_NCE"), + STM32_FUNCTION(13, "SDMMC1_D0"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(41, "PC9"), + STM32_FUNCTION(0, "GPIOC9"), + STM32_FUNCTION(1, "MCO2"), + STM32_FUNCTION(3, "TIM3_CH4"), + STM32_FUNCTION(4, "TIM8_CH4"), + STM32_FUNCTION(5, "I2C3_SDA"), + STM32_FUNCTION(6, "I2S_CKIN"), + STM32_FUNCTION(8, "UART5_CTS"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO0"), + STM32_FUNCTION(11, "LCD_G3"), + STM32_FUNCTION(13, "SDMMC1_D1"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(42, "PC10"), + STM32_FUNCTION(0, "GPIOC10"), + STM32_FUNCTION(4, "DFSDM_CKIN5"), + STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"), + STM32_FUNCTION(8, "USART3_TX"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO1"), + STM32_FUNCTION(13, "SDMMC1_D2"), + STM32_FUNCTION(14, "DCMI_D8"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(43, "PC11"), + STM32_FUNCTION(0, "GPIOC11"), + STM32_FUNCTION(4, "DFSDM_DATIN5"), + STM32_FUNCTION(7, "SPI3_MISO"), + STM32_FUNCTION(8, "USART3_RX"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "QUADSPI_BK2_NCS"), + STM32_FUNCTION(13, "SDMMC1_D3"), + STM32_FUNCTION(14, "DCMI_D4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(44, "PC12"), + STM32_FUNCTION(0, "GPIOC12"), + STM32_FUNCTION(1, "TRACED3"), + STM32_FUNCTION(7, "SPI3_MOSI I2S3_SD"), + STM32_FUNCTION(8, "USART3_CK"), + STM32_FUNCTION(9, "UART5_TX"), + STM32_FUNCTION(13, "SDMMC1_CK"), + STM32_FUNCTION(14, "DCMI_D9"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(45, "PC13"), + STM32_FUNCTION(0, "GPIOC13"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(46, "PC14"), + STM32_FUNCTION(0, "GPIOC14"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(47, "PC15"), + STM32_FUNCTION(0, "GPIOC15"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(48, "PD0"), + STM32_FUNCTION(0, "GPIOD0"), + STM32_FUNCTION(4, "DFSDM_CKIN6"), + STM32_FUNCTION(7, "DFSDM_DATIN7"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(13, "FMC_D2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(49, "PD1"), + STM32_FUNCTION(0, "GPIOD1"), + STM32_FUNCTION(4, "DFSDM_DATIN6"), + STM32_FUNCTION(7, "DFSDM_CKIN7"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(13, "FMC_D3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(50, "PD2"), + STM32_FUNCTION(0, "GPIOD2"), + STM32_FUNCTION(1, "TRACED2"), + STM32_FUNCTION(3, "TIM3_ETR"), + STM32_FUNCTION(9, "UART5_RX"), + STM32_FUNCTION(13, "SDMMC1_CMD"), + STM32_FUNCTION(14, "DCMI_D11"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(51, "PD3"), + STM32_FUNCTION(0, "GPIOD3"), + STM32_FUNCTION(4, "DFSDM_CKOUT"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(7, "DFSDM_DATIN0"), + STM32_FUNCTION(8, "USART2_CTS"), + STM32_FUNCTION(13, "FMC_CLK"), + STM32_FUNCTION(14, "DCMI_D5"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(52, "PD4"), + STM32_FUNCTION(0, "GPIOD4"), + STM32_FUNCTION(7, "DFSDM_CKIN0"), + STM32_FUNCTION(8, "USART2_RTS"), + STM32_FUNCTION(13, "FMC_NOE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(53, "PD5"), + STM32_FUNCTION(0, "GPIOD5"), + STM32_FUNCTION(8, "USART2_TX"), + STM32_FUNCTION(13, "FMC_NWE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(54, "PD6"), + STM32_FUNCTION(0, "GPIOD6"), + STM32_FUNCTION(4, "DFSDM_CKIN4"), + STM32_FUNCTION(6, "SPI3_MOSI I2S3_SD"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(8, "USART2_RX"), + STM32_FUNCTION(11, "DFSDM_DATIN1"), + STM32_FUNCTION(12, "SDMMC2_CK"), + STM32_FUNCTION(13, "FMC_NWAIT"), + STM32_FUNCTION(14, "DCMI_D10"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(55, "PD7"), + STM32_FUNCTION(0, "GPIOD7"), + STM32_FUNCTION(4, "DFSDM_DATIN4"), + STM32_FUNCTION(6, "SPI1_MOSI I2S1_SD"), + STM32_FUNCTION(7, "DFSDM_CKIN1"), + STM32_FUNCTION(8, "USART2_CK"), + STM32_FUNCTION(9, "SPDIF_RX0"), + STM32_FUNCTION(12, "SDMMC2_CMD"), + STM32_FUNCTION(13, "FMC_NE1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(56, "PD8"), + STM32_FUNCTION(0, "GPIOD8"), + STM32_FUNCTION(4, "DFSDM_CKIN3"), + STM32_FUNCTION(8, "USART3_TX"), + STM32_FUNCTION(9, "SPDIF_RX1"), + STM32_FUNCTION(13, "FMC_D13"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(57, "PD9"), + STM32_FUNCTION(0, "GPIOD9"), + STM32_FUNCTION(4, "DFSDM_DATIN3"), + STM32_FUNCTION(8, "USART3_RX"), + STM32_FUNCTION(13, "FMC_D14"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(58, "PD10"), + STM32_FUNCTION(0, "GPIOD10"), + STM32_FUNCTION(4, "DFSDM_CKOUT"), + STM32_FUNCTION(8, "USART3_CK"), + STM32_FUNCTION(13, "FMC_D15"), + STM32_FUNCTION(15, "LCD_B3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(59, "PD11"), + STM32_FUNCTION(0, "GPIOD11"), + STM32_FUNCTION(5, "I2C4_SMBA"), + STM32_FUNCTION(8, "USART3_CTS"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO0"), + STM32_FUNCTION(11, "SAI2_SD_A"), + STM32_FUNCTION(13, "FMC_A16 FMC_CLE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(60, "PD12"), + STM32_FUNCTION(0, "GPIOD12"), + STM32_FUNCTION(3, "TIM4_CH1"), + STM32_FUNCTION(4, "LPTIM1_IN1"), + STM32_FUNCTION(5, "I2C4_SCL"), + STM32_FUNCTION(8, "USART3_RTS"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO1"), + STM32_FUNCTION(11, "SAI2_FS_A"), + STM32_FUNCTION(13, "FMC_A17 FMC_ALE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(61, "PD13"), + STM32_FUNCTION(0, "GPIOD13"), + STM32_FUNCTION(3, "TIM4_CH2"), + STM32_FUNCTION(4, "LPTIM1_OUT"), + STM32_FUNCTION(5, "I2C4_SDA"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO3"), + STM32_FUNCTION(11, "SAI2_SCK_A"), + STM32_FUNCTION(13, "FMC_A18"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(62, "PD14"), + STM32_FUNCTION(0, "GPIOD14"), + STM32_FUNCTION(3, "TIM4_CH3"), + STM32_FUNCTION(9, "UART8_CTS"), + STM32_FUNCTION(13, "FMC_D0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(63, "PD15"), + STM32_FUNCTION(0, "GPIOD15"), + STM32_FUNCTION(3, "TIM4_CH4"), + STM32_FUNCTION(9, "UART8_RTS"), + STM32_FUNCTION(13, "FMC_D1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(64, "PE0"), + STM32_FUNCTION(0, "GPIOE0"), + STM32_FUNCTION(3, "TIM4_ETR"), + STM32_FUNCTION(4, "LPTIM1_ETR"), + STM32_FUNCTION(9, "UART8_RX"), + STM32_FUNCTION(11, "SAI2_MCLK_A"), + STM32_FUNCTION(13, "FMC_NBL0"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(65, "PE1"), + STM32_FUNCTION(0, "GPIOE1"), + STM32_FUNCTION(4, "LPTIM1_IN2"), + STM32_FUNCTION(9, "UART8_TX"), + STM32_FUNCTION(13, "FMC_NBL1"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(66, "PE2"), + STM32_FUNCTION(0, "GPIOE2"), + STM32_FUNCTION(1, "TRACECLK"), + STM32_FUNCTION(6, "SPI4_SCK"), + STM32_FUNCTION(7, "SAI1_MCLK_A"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO2"), + STM32_FUNCTION(12, "ETH_MII_TXD3"), + STM32_FUNCTION(13, "FMC_A23"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(67, "PE3"), + STM32_FUNCTION(0, "GPIOE3"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(7, "SAI1_SD_B"), + STM32_FUNCTION(13, "FMC_A19"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(68, "PE4"), + STM32_FUNCTION(0, "GPIOE4"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(6, "SPI4_NSS"), + STM32_FUNCTION(7, "SAI1_FS_A"), + STM32_FUNCTION(11, "DFSDM_DATIN3"), + STM32_FUNCTION(13, "FMC_A20"), + STM32_FUNCTION(14, "DCMI_D4"), + STM32_FUNCTION(15, "LCD_B0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(69, "PE5"), + STM32_FUNCTION(0, "GPIOE5"), + STM32_FUNCTION(1, "TRACED2"), + STM32_FUNCTION(4, "TIM9_CH1"), + STM32_FUNCTION(6, "SPI4_MISO"), + STM32_FUNCTION(7, "SAI1_SCK_A"), + STM32_FUNCTION(11, "DFSDM_CKIN3"), + STM32_FUNCTION(13, "FMC_A21"), + STM32_FUNCTION(14, "DCMI_D6"), + STM32_FUNCTION(15, "LCD_G0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(70, "PE6"), + STM32_FUNCTION(0, "GPIOE6"), + STM32_FUNCTION(1, "TRACED3"), + STM32_FUNCTION(2, "TIM1_BKIN2"), + STM32_FUNCTION(4, "TIM9_CH2"), + STM32_FUNCTION(6, "SPI4_MOSI"), + STM32_FUNCTION(7, "SAI1_SD_A"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(13, "FMC_A22"), + STM32_FUNCTION(14, "DCMI_D7"), + STM32_FUNCTION(15, "LCD_G1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(71, "PE7"), + STM32_FUNCTION(0, "GPIOE7"), + STM32_FUNCTION(2, "TIM1_ETR"), + STM32_FUNCTION(7, "DFSDM_DATIN2"), + STM32_FUNCTION(9, "UART7_RX"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO0"), + STM32_FUNCTION(13, "FMC_D4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(72, "PE8"), + STM32_FUNCTION(0, "GPIOE8"), + STM32_FUNCTION(2, "TIM1_CH1N"), + STM32_FUNCTION(7, "DFSDM_CKIN2"), + STM32_FUNCTION(9, "UART7_TX"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO1"), + STM32_FUNCTION(13, "FMC_D5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(73, "PE9"), + STM32_FUNCTION(0, "GPIOE9"), + STM32_FUNCTION(2, "TIM1_CH1"), + STM32_FUNCTION(7, "DFSDM_CKOUT"), + STM32_FUNCTION(9, "UART7_RTS"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO2"), + STM32_FUNCTION(13, "FMC_D6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(74, "PE10"), + STM32_FUNCTION(0, "GPIOE10"), + STM32_FUNCTION(2, "TIM1_CH2N"), + STM32_FUNCTION(7, "DFSDM_DATIN4"), + STM32_FUNCTION(9, "UART7_CTS"), + STM32_FUNCTION(11, "QUADSPI_BK2_IO3"), + STM32_FUNCTION(13, "FMC_D7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(75, "PE11"), + STM32_FUNCTION(0, "GPIOE11"), + STM32_FUNCTION(2, "TIM1_CH2"), + STM32_FUNCTION(6, "SPI4_NSS"), + STM32_FUNCTION(7, "DFSDM_CKIN4"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(13, "FMC_D8"), + STM32_FUNCTION(15, "LCD_G3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(76, "PE12"), + STM32_FUNCTION(0, "GPIOE12"), + STM32_FUNCTION(2, "TIM1_CH3N"), + STM32_FUNCTION(6, "SPI4_SCK"), + STM32_FUNCTION(7, "DFSDM_DATIN5"), + STM32_FUNCTION(11, "SAI2_SCK_B"), + STM32_FUNCTION(13, "FMC_D9"), + STM32_FUNCTION(15, "LCD_B4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(77, "PE13"), + STM32_FUNCTION(0, "GPIOE13"), + STM32_FUNCTION(2, "TIM1_CH3"), + STM32_FUNCTION(6, "SPI4_MISO"), + STM32_FUNCTION(7, "DFSDM_CKIN5"), + STM32_FUNCTION(11, "SAI2_FS_B"), + STM32_FUNCTION(13, "FMC_D10"), + STM32_FUNCTION(15, "LCD_DE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(78, "PE14"), + STM32_FUNCTION(0, "GPIOE14"), + STM32_FUNCTION(2, "TIM1_CH4"), + STM32_FUNCTION(6, "SPI4_MOSI"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(13, "FMC_D11"), + STM32_FUNCTION(15, "LCD_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(79, "PE15"), + STM32_FUNCTION(0, "GPIOE15"), + STM32_FUNCTION(2, "TIM1_BKIN"), + STM32_FUNCTION(13, "FMC_D12"), + STM32_FUNCTION(15, "LCD_R7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(80, "PF0"), + STM32_FUNCTION(0, "GPIOF0"), + STM32_FUNCTION(5, "I2C2_SDA"), + STM32_FUNCTION(13, "FMC_A0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(81, "PF1"), + STM32_FUNCTION(0, "GPIOF1"), + STM32_FUNCTION(5, "I2C2_SCL"), + STM32_FUNCTION(13, "FMC_A1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(82, "PF2"), + STM32_FUNCTION(0, "GPIOF2"), + STM32_FUNCTION(5, "I2C2_SMBA"), + STM32_FUNCTION(13, "FMC_A2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(83, "PF3"), + STM32_FUNCTION(0, "GPIOF3"), + STM32_FUNCTION(13, "FMC_A3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(84, "PF4"), + STM32_FUNCTION(0, "GPIOF4"), + STM32_FUNCTION(13, "FMC_A4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(85, "PF5"), + STM32_FUNCTION(0, "GPIOF5"), + STM32_FUNCTION(13, "FMC_A5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(86, "PF6"), + STM32_FUNCTION(0, "GPIOF6"), + STM32_FUNCTION(4, "TIM10_CH1"), + STM32_FUNCTION(6, "SPI5_NSS"), + STM32_FUNCTION(7, "SAI1_SD_B"), + STM32_FUNCTION(9, "UART7_RX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(87, "PF7"), + STM32_FUNCTION(0, "GPIOF7"), + STM32_FUNCTION(4, "TIM11_CH1"), + STM32_FUNCTION(6, "SPI5_SCK"), + STM32_FUNCTION(7, "SAI1_MCLK_B"), + STM32_FUNCTION(9, "UART7_TX"), + STM32_FUNCTION(10, "QUADSPI_BK1_IO2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(88, "PF8"), + STM32_FUNCTION(0, "GPIOF8"), + STM32_FUNCTION(6, "SPI5_MISO"), + STM32_FUNCTION(7, "SAI1_SCK_B"), + STM32_FUNCTION(9, "UART7_RTS"), + STM32_FUNCTION(10, "TIM13_CH1"), + STM32_FUNCTION(11, "QUADSPI_BK1_IO0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(89, "PF9"), + STM32_FUNCTION(0, "GPIOF9"), + STM32_FUNCTION(6, "SPI5_MOSI"), + STM32_FUNCTION(7, "SAI1_FS_B"), + STM32_FUNCTION(9, "UART7_CTS"), + STM32_FUNCTION(10, "TIM14_CH1"), + STM32_FUNCTION(11, "QUADSPI_BK1_IO1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(90, "PF10"), + STM32_FUNCTION(0, "GPIOF10"), + STM32_FUNCTION(10, "QUADSPI_CLK"), + STM32_FUNCTION(14, "DCMI_D11"), + STM32_FUNCTION(15, "LCD_DE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(91, "PF11"), + STM32_FUNCTION(0, "GPIOF11"), + STM32_FUNCTION(6, "SPI5_MOSI"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(13, "FMC_SDNRAS"), + STM32_FUNCTION(14, "DCMI_D12"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(92, "PF12"), + STM32_FUNCTION(0, "GPIOF12"), + STM32_FUNCTION(13, "FMC_A6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(93, "PF13"), + STM32_FUNCTION(0, "GPIOF13"), + STM32_FUNCTION(5, "I2C4_SMBA"), + STM32_FUNCTION(7, "DFSDM_DATIN6"), + STM32_FUNCTION(13, "FMC_A7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(94, "PF14"), + STM32_FUNCTION(0, "GPIOF14"), + STM32_FUNCTION(5, "I2C4_SCL"), + STM32_FUNCTION(7, "DFSDM_CKIN6"), + STM32_FUNCTION(13, "FMC_A8"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(95, "PF15"), + STM32_FUNCTION(0, "GPIOF15"), + STM32_FUNCTION(5, "I2C4_SDA"), + STM32_FUNCTION(13, "FMC_A9"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(96, "PG0"), + STM32_FUNCTION(0, "GPIOG0"), + STM32_FUNCTION(13, "FMC_A10"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(97, "PG1"), + STM32_FUNCTION(0, "GPIOG1"), + STM32_FUNCTION(13, "FMC_A11"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(98, "PG2"), + STM32_FUNCTION(0, "GPIOG2"), + STM32_FUNCTION(13, "FMC_A12"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(99, "PG3"), + STM32_FUNCTION(0, "GPIOG3"), + STM32_FUNCTION(13, "FMC_A13"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(100, "PG4"), + STM32_FUNCTION(0, "GPIOG4"), + STM32_FUNCTION(13, "FMC_A14 FMC_BA0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(101, "PG5"), + STM32_FUNCTION(0, "GPIOG5"), + STM32_FUNCTION(13, "FMC_A15 FMC_BA1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(102, "PG6"), + STM32_FUNCTION(0, "GPIOG6"), + STM32_FUNCTION(13, "FMC_NE3"), + STM32_FUNCTION(14, "DCMI_D12"), + STM32_FUNCTION(15, "LCD_R7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(103, "PG7"), + STM32_FUNCTION(0, "GPIOG7"), + STM32_FUNCTION(7, "SAI1_MCLK_A"), + STM32_FUNCTION(9, "USART6_CK"), + STM32_FUNCTION(13, "FMC_INT"), + STM32_FUNCTION(14, "DCMI_D13"), + STM32_FUNCTION(15, "LCD_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(104, "PG8"), + STM32_FUNCTION(0, "GPIOG8"), + STM32_FUNCTION(6, "SPI6_NSS"), + STM32_FUNCTION(8, "SPDIF_RX2"), + STM32_FUNCTION(9, "USART6_RTS"), + STM32_FUNCTION(12, "ETH_PPS_OUT"), + STM32_FUNCTION(13, "FMC_SDCLK"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(105, "PG9"), + STM32_FUNCTION(0, "GPIOG9"), + STM32_FUNCTION(6, "SPI1_MISO"), + STM32_FUNCTION(8, "SPDIF_RX3"), + STM32_FUNCTION(9, "USART6_RX"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO2"), + STM32_FUNCTION(11, "SAI2_FS_B"), + STM32_FUNCTION(12, "SDMMC2_D0"), + STM32_FUNCTION(13, "FMC_NE2 FMC_NCE"), + STM32_FUNCTION(14, "DCMI_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(106, "PG10"), + STM32_FUNCTION(0, "GPIOG10"), + STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), + STM32_FUNCTION(10, "LCD_G3"), + STM32_FUNCTION(11, "SAI2_SD_B"), + STM32_FUNCTION(12, "SDMMC2_D1"), + STM32_FUNCTION(13, "FMC_NE3"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(107, "PG11"), + STM32_FUNCTION(0, "GPIOG11"), + STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"), + STM32_FUNCTION(8, "SPDIF_RX0"), + STM32_FUNCTION(11, "SDMMC2_D2"), + STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(15, "LCD_B3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(108, "PG12"), + STM32_FUNCTION(0, "GPIOG12"), + STM32_FUNCTION(4, "LPTIM1_IN1"), + STM32_FUNCTION(6, "SPI6_MISO"), + STM32_FUNCTION(8, "SPDIF_RX1"), + STM32_FUNCTION(9, "USART6_RTS"), + STM32_FUNCTION(10, "LCD_B4"), + STM32_FUNCTION(12, "SDMMC2_D3"), + STM32_FUNCTION(13, "FMC_NE4"), + STM32_FUNCTION(15, "LCD_B1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(109, "PG13"), + STM32_FUNCTION(0, "GPIOG13"), + STM32_FUNCTION(1, "TRACED0"), + STM32_FUNCTION(4, "LPTIM1_OUT"), + STM32_FUNCTION(6, "SPI6_SCK"), + STM32_FUNCTION(9, "USART6_CTS"), + STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"), + STM32_FUNCTION(13, "FMC_A24"), + STM32_FUNCTION(15, "LCD_R0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(110, "PG14"), + STM32_FUNCTION(0, "GPIOG14"), + STM32_FUNCTION(1, "TRACED1"), + STM32_FUNCTION(4, "LPTIM1_ETR"), + STM32_FUNCTION(6, "SPI6_MOSI"), + STM32_FUNCTION(9, "USART6_TX"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO3"), + STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"), + STM32_FUNCTION(13, "FMC_A25"), + STM32_FUNCTION(15, "LCD_B0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(111, "PG15"), + STM32_FUNCTION(0, "GPIOG15"), + STM32_FUNCTION(9, "USART6_CTS"), + STM32_FUNCTION(13, "FMC_SDNCAS"), + STM32_FUNCTION(14, "DCMI_D13"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(112, "PH0"), + STM32_FUNCTION(0, "GPIOH0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(113, "PH1"), + STM32_FUNCTION(0, "GPIOH1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(114, "PH2"), + STM32_FUNCTION(0, "GPIOH2"), + STM32_FUNCTION(4, "LPTIM1_IN2"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO0"), + STM32_FUNCTION(11, "SAI2_SCK_B"), + STM32_FUNCTION(12, "ETH_MII_CRS"), + STM32_FUNCTION(13, "FMC_SDCKE0"), + STM32_FUNCTION(15, "LCD_R0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(115, "PH3"), + STM32_FUNCTION(0, "GPIOH3"), + STM32_FUNCTION(10, "QUADSPI_BK2_IO1"), + STM32_FUNCTION(11, "SAI2_MCLK_B"), + STM32_FUNCTION(12, "ETH_MII_COL"), + STM32_FUNCTION(13, "FMC_SDNE0"), + STM32_FUNCTION(15, "LCD_R1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(116, "PH4"), + STM32_FUNCTION(0, "GPIOH4"), + STM32_FUNCTION(5, "I2C2_SCL"), + STM32_FUNCTION(10, "LCD_G5"), + STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(117, "PH5"), + STM32_FUNCTION(0, "GPIOH5"), + STM32_FUNCTION(5, "I2C2_SDA"), + STM32_FUNCTION(6, "SPI5_NSS"), + STM32_FUNCTION(13, "FMC_SDNWE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(118, "PH6"), + STM32_FUNCTION(0, "GPIOH6"), + STM32_FUNCTION(5, "I2C2_SMBA"), + STM32_FUNCTION(6, "SPI5_SCK"), + STM32_FUNCTION(10, "TIM12_CH1"), + STM32_FUNCTION(12, "ETH_MII_RXD2"), + STM32_FUNCTION(13, "FMC_SDNE1"), + STM32_FUNCTION(14, "DCMI_D8"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(119, "PH7"), + STM32_FUNCTION(0, "GPIOH7"), + STM32_FUNCTION(5, "I2C3_SCL"), + STM32_FUNCTION(6, "SPI5_MISO"), + STM32_FUNCTION(12, "ETH_MII_RXD3"), + STM32_FUNCTION(13, "FMC_SDCKE1"), + STM32_FUNCTION(14, "DCMI_D9"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(120, "PH8"), + STM32_FUNCTION(0, "GPIOH8"), + STM32_FUNCTION(5, "I2C3_SDA"), + STM32_FUNCTION(13, "FMC_D16"), + STM32_FUNCTION(14, "DCMI_HSYNC"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(121, "PH9"), + STM32_FUNCTION(0, "GPIOH9"), + STM32_FUNCTION(5, "I2C3_SMBA"), + STM32_FUNCTION(10, "TIM12_CH2"), + STM32_FUNCTION(13, "FMC_D17"), + STM32_FUNCTION(14, "DCMI_D0"), + STM32_FUNCTION(15, "LCD_R3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(122, "PH10"), + STM32_FUNCTION(0, "GPIOH10"), + STM32_FUNCTION(3, "TIM5_CH1"), + STM32_FUNCTION(5, "I2C4_SMBA"), + STM32_FUNCTION(13, "FMC_D18"), + STM32_FUNCTION(14, "DCMI_D1"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(123, "PH11"), + STM32_FUNCTION(0, "GPIOH11"), + STM32_FUNCTION(3, "TIM5_CH2"), + STM32_FUNCTION(5, "I2C4_SCL"), + STM32_FUNCTION(13, "FMC_D19"), + STM32_FUNCTION(14, "DCMI_D2"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(124, "PH12"), + STM32_FUNCTION(0, "GPIOH12"), + STM32_FUNCTION(3, "TIM5_CH3"), + STM32_FUNCTION(5, "I2C4_SDA"), + STM32_FUNCTION(13, "FMC_D20"), + STM32_FUNCTION(14, "DCMI_D3"), + STM32_FUNCTION(15, "LCD_R6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(125, "PH13"), + STM32_FUNCTION(0, "GPIOH13"), + STM32_FUNCTION(4, "TIM8_CH1N"), + STM32_FUNCTION(9, "UART4_TX"), + STM32_FUNCTION(10, "CAN1_TX"), + STM32_FUNCTION(13, "FMC_D21"), + STM32_FUNCTION(15, "LCD_G2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(126, "PH14"), + STM32_FUNCTION(0, "GPIOH14"), + STM32_FUNCTION(4, "TIM8_CH2N"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(13, "FMC_D22"), + STM32_FUNCTION(14, "DCMI_D4"), + STM32_FUNCTION(15, "LCD_G3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(127, "PH15"), + STM32_FUNCTION(0, "GPIOH15"), + STM32_FUNCTION(4, "TIM8_CH3N"), + STM32_FUNCTION(13, "FMC_D23"), + STM32_FUNCTION(14, "DCMI_D11"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(128, "PI0"), + STM32_FUNCTION(0, "GPIOI0"), + STM32_FUNCTION(3, "TIM5_CH4"), + STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), + STM32_FUNCTION(13, "FMC_D24"), + STM32_FUNCTION(14, "DCMI_D13"), + STM32_FUNCTION(15, "LCD_G5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(129, "PI1"), + STM32_FUNCTION(0, "GPIOI1"), + STM32_FUNCTION(4, "TIM8_BKIN2"), + STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), + STM32_FUNCTION(13, "FMC_D25"), + STM32_FUNCTION(14, "DCMI_D8"), + STM32_FUNCTION(15, "LCD_G6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(130, "PI2"), + STM32_FUNCTION(0, "GPIOI2"), + STM32_FUNCTION(4, "TIM8_CH4"), + STM32_FUNCTION(6, "SPI2_MISO"), + STM32_FUNCTION(13, "FMC_D26"), + STM32_FUNCTION(14, "DCMI_D9"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(131, "PI3"), + STM32_FUNCTION(0, "GPIOI3"), + STM32_FUNCTION(4, "TIM8_ETR"), + STM32_FUNCTION(6, "SPI2_MOSI I2S2_SD"), + STM32_FUNCTION(13, "FMC_D27"), + STM32_FUNCTION(14, "DCMI_D10"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(132, "PI4"), + STM32_FUNCTION(0, "GPIOI4"), + STM32_FUNCTION(4, "TIM8_BKIN"), + STM32_FUNCTION(11, "SAI2_MCLK_A"), + STM32_FUNCTION(13, "FMC_NBL2"), + STM32_FUNCTION(14, "DCMI_D5"), + STM32_FUNCTION(15, "LCD_B4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(133, "PI5"), + STM32_FUNCTION(0, "GPIOI5"), + STM32_FUNCTION(4, "TIM8_CH1"), + STM32_FUNCTION(11, "SAI2_SCK_A"), + STM32_FUNCTION(13, "FMC_NBL3"), + STM32_FUNCTION(14, "DCMI_VSYNC"), + STM32_FUNCTION(15, "LCD_B5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(134, "PI6"), + STM32_FUNCTION(0, "GPIOI6"), + STM32_FUNCTION(4, "TIM8_CH2"), + STM32_FUNCTION(11, "SAI2_SD_A"), + STM32_FUNCTION(13, "FMC_D28"), + STM32_FUNCTION(14, "DCMI_D6"), + STM32_FUNCTION(15, "LCD_B6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(135, "PI7"), + STM32_FUNCTION(0, "GPIOI7"), + STM32_FUNCTION(4, "TIM8_CH3"), + STM32_FUNCTION(11, "SAI2_FS_A"), + STM32_FUNCTION(13, "FMC_D29"), + STM32_FUNCTION(14, "DCMI_D7"), + STM32_FUNCTION(15, "LCD_B7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(136, "PI8"), + STM32_FUNCTION(0, "GPIOI8"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(137, "PI9"), + STM32_FUNCTION(0, "GPIOI9"), + STM32_FUNCTION(9, "UART4_RX"), + STM32_FUNCTION(10, "CAN1_RX"), + STM32_FUNCTION(13, "FMC_D30"), + STM32_FUNCTION(15, "LCD_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(138, "PI10"), + STM32_FUNCTION(0, "GPIOI10"), + STM32_FUNCTION(12, "ETH_MII_RX_ER"), + STM32_FUNCTION(13, "FMC_D31"), + STM32_FUNCTION(15, "LCD_HSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(139, "PI11"), + STM32_FUNCTION(0, "GPIOI11"), + STM32_FUNCTION(10, "LCD_G6"), + STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(140, "PI12"), + STM32_FUNCTION(0, "GPIOI12"), + STM32_FUNCTION(15, "LCD_HSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(141, "PI13"), + STM32_FUNCTION(0, "GPIOI13"), + STM32_FUNCTION(15, "LCD_VSYNC"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(142, "PI14"), + STM32_FUNCTION(0, "GPIOI14"), + STM32_FUNCTION(15, "LCD_CLK"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(143, "PI15"), + STM32_FUNCTION(0, "GPIOI15"), + STM32_FUNCTION(10, "LCD_G2"), + STM32_FUNCTION(15, "LCD_R0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(144, "PJ0"), + STM32_FUNCTION(0, "GPIOJ0"), + STM32_FUNCTION(10, "LCD_R7"), + STM32_FUNCTION(15, "LCD_R1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(145, "PJ1"), + STM32_FUNCTION(0, "GPIOJ1"), + STM32_FUNCTION(15, "LCD_R2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(146, "PJ2"), + STM32_FUNCTION(0, "GPIOJ2"), + STM32_FUNCTION(14, "DSI_TE"), + STM32_FUNCTION(15, "LCD_R3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(147, "PJ3"), + STM32_FUNCTION(0, "GPIOJ3"), + STM32_FUNCTION(15, "LCD_R4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(148, "PJ4"), + STM32_FUNCTION(0, "GPIOJ4"), + STM32_FUNCTION(15, "LCD_R5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(149, "PJ5"), + STM32_FUNCTION(0, "GPIOJ5"), + STM32_FUNCTION(15, "LCD_R6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(150, "PJ6"), + STM32_FUNCTION(0, "GPIOJ6"), + STM32_FUNCTION(15, "LCD_R7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(151, "PJ7"), + STM32_FUNCTION(0, "GPIOJ7"), + STM32_FUNCTION(15, "LCD_G0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(152, "PJ8"), + STM32_FUNCTION(0, "GPIOJ8"), + STM32_FUNCTION(15, "LCD_G1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(153, "PJ9"), + STM32_FUNCTION(0, "GPIOJ9"), + STM32_FUNCTION(15, "LCD_G2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(154, "PJ10"), + STM32_FUNCTION(0, "GPIOJ10"), + STM32_FUNCTION(15, "LCD_G3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(155, "PJ11"), + STM32_FUNCTION(0, "GPIOJ11"), + STM32_FUNCTION(15, "LCD_G4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(156, "PJ12"), + STM32_FUNCTION(0, "GPIOJ12"), + STM32_FUNCTION(10, "LCD_G3"), + STM32_FUNCTION(15, "LCD_B0"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(157, "PJ13"), + STM32_FUNCTION(0, "GPIOJ13"), + STM32_FUNCTION(10, "LCD_G4"), + STM32_FUNCTION(15, "LCD_B1"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(158, "PJ14"), + STM32_FUNCTION(0, "GPIOJ14"), + STM32_FUNCTION(15, "LCD_B2"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(159, "PJ15"), + STM32_FUNCTION(0, "GPIOJ15"), + STM32_FUNCTION(15, "LCD_B3"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(160, "PK0"), + STM32_FUNCTION(0, "GPIOK0"), + STM32_FUNCTION(15, "LCD_G5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(161, "PK1"), + STM32_FUNCTION(0, "GPIOK1"), + STM32_FUNCTION(15, "LCD_G6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(162, "PK2"), + STM32_FUNCTION(0, "GPIOK2"), + STM32_FUNCTION(15, "LCD_G7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(163, "PK3"), + STM32_FUNCTION(0, "GPIOK3"), + STM32_FUNCTION(15, "LCD_B4"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(164, "PK4"), + STM32_FUNCTION(0, "GPIOK4"), + STM32_FUNCTION(15, "LCD_B5"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(165, "PK5"), + STM32_FUNCTION(0, "GPIOK5"), + STM32_FUNCTION(15, "LCD_B6"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(166, "PK6"), + STM32_FUNCTION(0, "GPIOK6"), + STM32_FUNCTION(15, "LCD_B7"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), + STM32_PIN( + PINCTRL_PIN(167, "PK7"), + STM32_FUNCTION(0, "GPIOK7"), + STM32_FUNCTION(15, "LCD_DE"), + STM32_FUNCTION(16, "EVENTOUT"), + STM32_FUNCTION(17, "ANALOG") + ), +}; + +static struct stm32_pinctrl_match_data stm32f769_match_data = { + .pins = stm32f769_pins, + .npins = ARRAY_SIZE(stm32f769_pins), +}; + +static const struct of_device_id stm32f769_pctrl_match[] = { + { + .compatible = "st,stm32f769-pinctrl", + .data = &stm32f769_match_data, + }, + { } +}; + +static struct platform_driver stm32f769_pinctrl_driver = { + .probe = stm32_pctl_probe, + .driver = { + .name = "stm32f769-pinctrl", + .of_match_table = stm32f769_pctrl_match, + }, +}; + +static int __init stm32f769_pinctrl_init(void) +{ + return platform_driver_register(&stm32f769_pinctrl_driver); +} +arch_initcall(stm32f769_pinctrl_init); -- cgit From 470b73a38470e8baf923b8424b5f54870efaef22 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 19 Jan 2018 16:18:19 +0100 Subject: pinctrl: sunxi: Use of_clk_get_parent_count() instead of open coding Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 131adf7953cd..341312d66512 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -1187,7 +1188,7 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, int i, ret; /* Deal with old DTs that didn't have the oscillators */ - if (of_count_phandle_with_args(node, "clocks", "#clock-cells") != 3) + if (of_clk_get_parent_count(node) != 3) return 0; /* If we don't have any setup, bail out */ -- cgit From 5ef3166e8a32d78dfa985a323aa45ed485ff663a Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 23 Jan 2018 12:31:41 +0100 Subject: ocxl: Driver code for 'generic' opencapi devices Add an ocxl driver to handle generic opencapi devices. Of course, it's not meant to be the only opencapi driver, any device is free to implement its own. But if a host application only needs basic services like attaching to an opencapi adapter, have translation faults handled or allocate AFU interrupts, it should suffice. The AFU config space must follow the opencapi specification and use the expected vendor/device ID to be seen by the generic driver. The driver exposes the device AFUs as a char device in /dev/ocxl/ Note that the driver currently doesn't handle memory attached to the opencapi device. Signed-off-by: Frederic Barrat Signed-off-by: Andrew Donnellan Signed-off-by: Alastair D'Silva Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/config.c | 712 ++++++++++++++++++++++++++++++++++++++ drivers/misc/ocxl/context.c | 230 ++++++++++++ drivers/misc/ocxl/file.c | 398 +++++++++++++++++++++ drivers/misc/ocxl/link.c | 603 ++++++++++++++++++++++++++++++++ drivers/misc/ocxl/main.c | 33 ++ drivers/misc/ocxl/ocxl_internal.h | 193 +++++++++++ drivers/misc/ocxl/pasid.c | 107 ++++++ drivers/misc/ocxl/pci.c | 585 +++++++++++++++++++++++++++++++ drivers/misc/ocxl/sysfs.c | 142 ++++++++ 9 files changed, 3003 insertions(+) create mode 100644 drivers/misc/ocxl/config.c create mode 100644 drivers/misc/ocxl/context.c create mode 100644 drivers/misc/ocxl/file.c create mode 100644 drivers/misc/ocxl/link.c create mode 100644 drivers/misc/ocxl/main.c create mode 100644 drivers/misc/ocxl/ocxl_internal.h create mode 100644 drivers/misc/ocxl/pasid.c create mode 100644 drivers/misc/ocxl/pci.c create mode 100644 drivers/misc/ocxl/sysfs.c (limited to 'drivers') diff --git a/drivers/misc/ocxl/config.c b/drivers/misc/ocxl/config.c new file mode 100644 index 000000000000..ea8cca50ea06 --- /dev/null +++ b/drivers/misc/ocxl/config.c @@ -0,0 +1,712 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include +#include +#include "ocxl_internal.h" + +#define EXTRACT_BIT(val, bit) (!!(val & BIT(bit))) +#define EXTRACT_BITS(val, s, e) ((val & GENMASK(e, s)) >> s) + +#define OCXL_DVSEC_AFU_IDX_MASK GENMASK(5, 0) +#define OCXL_DVSEC_ACTAG_MASK GENMASK(11, 0) +#define OCXL_DVSEC_PASID_MASK GENMASK(19, 0) +#define OCXL_DVSEC_PASID_LOG_MASK GENMASK(4, 0) + +#define OCXL_DVSEC_TEMPL_VERSION 0x0 +#define OCXL_DVSEC_TEMPL_NAME 0x4 +#define OCXL_DVSEC_TEMPL_AFU_VERSION 0x1C +#define OCXL_DVSEC_TEMPL_MMIO_GLOBAL 0x20 +#define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28 +#define OCXL_DVSEC_TEMPL_MMIO_PP 0x30 +#define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38 +#define OCXL_DVSEC_TEMPL_MEM_SZ 0x3C +#define OCXL_DVSEC_TEMPL_WWID 0x40 + +#define OCXL_MAX_AFU_PER_FUNCTION 64 +#define OCXL_TEMPL_LEN 0x58 +#define OCXL_TEMPL_NAME_LEN 24 +#define OCXL_CFG_TIMEOUT 3 + +static int find_dvsec(struct pci_dev *dev, int dvsec_id) +{ + int vsec = 0; + u16 vendor, id; + + while ((vsec = pci_find_next_ext_capability(dev, vsec, + OCXL_EXT_CAP_ID_DVSEC))) { + pci_read_config_word(dev, vsec + OCXL_DVSEC_VENDOR_OFFSET, + &vendor); + pci_read_config_word(dev, vsec + OCXL_DVSEC_ID_OFFSET, &id); + if (vendor == PCI_VENDOR_ID_IBM && id == dvsec_id) + return vsec; + } + return 0; +} + +static int find_dvsec_afu_ctrl(struct pci_dev *dev, u8 afu_idx) +{ + int vsec = 0; + u16 vendor, id; + u8 idx; + + while ((vsec = pci_find_next_ext_capability(dev, vsec, + OCXL_EXT_CAP_ID_DVSEC))) { + pci_read_config_word(dev, vsec + OCXL_DVSEC_VENDOR_OFFSET, + &vendor); + pci_read_config_word(dev, vsec + OCXL_DVSEC_ID_OFFSET, &id); + + if (vendor == PCI_VENDOR_ID_IBM && + id == OCXL_DVSEC_AFU_CTRL_ID) { + pci_read_config_byte(dev, + vsec + OCXL_DVSEC_AFU_CTRL_AFU_IDX, + &idx); + if (idx == afu_idx) + return vsec; + } + } + return 0; +} + +static int read_pasid(struct pci_dev *dev, struct ocxl_fn_config *fn) +{ + u16 val; + int pos; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PASID); + if (!pos) { + /* + * PASID capability is not mandatory, but there + * shouldn't be any AFU + */ + dev_dbg(&dev->dev, "Function doesn't require any PASID\n"); + fn->max_pasid_log = -1; + goto out; + } + pci_read_config_word(dev, pos + PCI_PASID_CAP, &val); + fn->max_pasid_log = EXTRACT_BITS(val, 8, 12); + +out: + dev_dbg(&dev->dev, "PASID capability:\n"); + dev_dbg(&dev->dev, " Max PASID log = %d\n", fn->max_pasid_log); + return 0; +} + +static int read_dvsec_tl(struct pci_dev *dev, struct ocxl_fn_config *fn) +{ + int pos; + + pos = find_dvsec(dev, OCXL_DVSEC_TL_ID); + if (!pos && PCI_FUNC(dev->devfn) == 0) { + dev_err(&dev->dev, "Can't find TL DVSEC\n"); + return -ENODEV; + } + if (pos && PCI_FUNC(dev->devfn) != 0) { + dev_err(&dev->dev, "TL DVSEC is only allowed on function 0\n"); + return -ENODEV; + } + fn->dvsec_tl_pos = pos; + return 0; +} + +static int read_dvsec_function(struct pci_dev *dev, struct ocxl_fn_config *fn) +{ + int pos, afu_present; + u32 val; + + pos = find_dvsec(dev, OCXL_DVSEC_FUNC_ID); + if (!pos) { + dev_err(&dev->dev, "Can't find function DVSEC\n"); + return -ENODEV; + } + fn->dvsec_function_pos = pos; + + pci_read_config_dword(dev, pos + OCXL_DVSEC_FUNC_OFF_INDEX, &val); + afu_present = EXTRACT_BIT(val, 31); + if (!afu_present) { + fn->max_afu_index = -1; + dev_dbg(&dev->dev, "Function doesn't define any AFU\n"); + goto out; + } + fn->max_afu_index = EXTRACT_BITS(val, 24, 29); + +out: + dev_dbg(&dev->dev, "Function DVSEC:\n"); + dev_dbg(&dev->dev, " Max AFU index = %d\n", fn->max_afu_index); + return 0; +} + +static int read_dvsec_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn) +{ + int pos; + + if (fn->max_afu_index < 0) { + fn->dvsec_afu_info_pos = -1; + return 0; + } + + pos = find_dvsec(dev, OCXL_DVSEC_AFU_INFO_ID); + if (!pos) { + dev_err(&dev->dev, "Can't find AFU information DVSEC\n"); + return -ENODEV; + } + fn->dvsec_afu_info_pos = pos; + return 0; +} + +static int read_dvsec_vendor(struct pci_dev *dev) +{ + int pos; + u32 cfg, tlx, dlx; + + /* + * vendor specific DVSEC is optional + * + * It's currently only used on function 0 to specify the + * version of some logic blocks. Some older images may not + * even have it so we ignore any errors + */ + if (PCI_FUNC(dev->devfn) != 0) + return 0; + + pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID); + if (!pos) + return 0; + + pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_CFG_VERS, &cfg); + pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_TLX_VERS, &tlx); + pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_DLX_VERS, &dlx); + + dev_dbg(&dev->dev, "Vendor specific DVSEC:\n"); + dev_dbg(&dev->dev, " CFG version = 0x%x\n", cfg); + dev_dbg(&dev->dev, " TLX version = 0x%x\n", tlx); + dev_dbg(&dev->dev, " DLX version = 0x%x\n", dlx); + return 0; +} + +static int validate_function(struct pci_dev *dev, struct ocxl_fn_config *fn) +{ + if (fn->max_pasid_log == -1 && fn->max_afu_index >= 0) { + dev_err(&dev->dev, + "AFUs are defined but no PASIDs are requested\n"); + return -EINVAL; + } + + if (fn->max_afu_index > OCXL_MAX_AFU_PER_FUNCTION) { + dev_err(&dev->dev, + "Max AFU index out of architectural limit (%d vs %d)\n", + fn->max_afu_index, OCXL_MAX_AFU_PER_FUNCTION); + return -EINVAL; + } + return 0; +} + +int ocxl_config_read_function(struct pci_dev *dev, struct ocxl_fn_config *fn) +{ + int rc; + + rc = read_pasid(dev, fn); + if (rc) { + dev_err(&dev->dev, "Invalid PASID configuration: %d\n", rc); + return -ENODEV; + } + + rc = read_dvsec_tl(dev, fn); + if (rc) { + dev_err(&dev->dev, + "Invalid Transaction Layer DVSEC configuration: %d\n", + rc); + return -ENODEV; + } + + rc = read_dvsec_function(dev, fn); + if (rc) { + dev_err(&dev->dev, + "Invalid Function DVSEC configuration: %d\n", rc); + return -ENODEV; + } + + rc = read_dvsec_afu_info(dev, fn); + if (rc) { + dev_err(&dev->dev, "Invalid AFU configuration: %d\n", rc); + return -ENODEV; + } + + rc = read_dvsec_vendor(dev); + if (rc) { + dev_err(&dev->dev, + "Invalid vendor specific DVSEC configuration: %d\n", + rc); + return -ENODEV; + } + + rc = validate_function(dev, fn); + return rc; +} + +static int read_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn, + int offset, u32 *data) +{ + u32 val; + unsigned long timeout = jiffies + (HZ * OCXL_CFG_TIMEOUT); + int pos = fn->dvsec_afu_info_pos; + + /* Protect 'data valid' bit */ + if (EXTRACT_BIT(offset, 31)) { + dev_err(&dev->dev, "Invalid offset in AFU info DVSEC\n"); + return -EINVAL; + } + + pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_OFF, offset); + pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_OFF, &val); + while (!EXTRACT_BIT(val, 31)) { + if (time_after_eq(jiffies, timeout)) { + dev_err(&dev->dev, + "Timeout while reading AFU info DVSEC (offset=%d)\n", + offset); + return -EBUSY; + } + cpu_relax(); + pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_OFF, &val); + } + pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_DATA, data); + return 0; +} + +int ocxl_config_check_afu_index(struct pci_dev *dev, + struct ocxl_fn_config *fn, int afu_idx) +{ + u32 val; + int rc, templ_major, templ_minor, len; + + pci_write_config_word(dev, fn->dvsec_afu_info_pos, afu_idx); + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val); + if (rc) + return rc; + + /* AFU index map can have holes */ + if (!val) + return 0; + + templ_major = EXTRACT_BITS(val, 8, 15); + templ_minor = EXTRACT_BITS(val, 0, 7); + dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n", + templ_major, templ_minor); + + len = EXTRACT_BITS(val, 16, 31); + if (len != OCXL_TEMPL_LEN) { + dev_warn(&dev->dev, + "Unexpected template length in AFU information (%#x)\n", + len); + } + return 1; +} + +static int read_afu_name(struct pci_dev *dev, struct ocxl_fn_config *fn, + struct ocxl_afu_config *afu) +{ + int i, rc; + u32 val, *ptr; + + BUILD_BUG_ON(OCXL_AFU_NAME_SZ < OCXL_TEMPL_NAME_LEN); + for (i = 0; i < OCXL_TEMPL_NAME_LEN; i += 4) { + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_NAME + i, &val); + if (rc) + return rc; + ptr = (u32 *) &afu->name[i]; + *ptr = val; + } + afu->name[OCXL_AFU_NAME_SZ - 1] = '\0'; /* play safe */ + return 0; +} + +static int read_afu_mmio(struct pci_dev *dev, struct ocxl_fn_config *fn, + struct ocxl_afu_config *afu) +{ + int rc; + u32 val; + + /* + * Global MMIO + */ + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_GLOBAL, &val); + if (rc) + return rc; + afu->global_mmio_bar = EXTRACT_BITS(val, 0, 2); + afu->global_mmio_offset = EXTRACT_BITS(val, 16, 31) << 16; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_GLOBAL + 4, &val); + if (rc) + return rc; + afu->global_mmio_offset += (u64) val << 32; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ, &val); + if (rc) + return rc; + afu->global_mmio_size = val; + + /* + * Per-process MMIO + */ + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_PP, &val); + if (rc) + return rc; + afu->pp_mmio_bar = EXTRACT_BITS(val, 0, 2); + afu->pp_mmio_offset = EXTRACT_BITS(val, 16, 31) << 16; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_PP + 4, &val); + if (rc) + return rc; + afu->pp_mmio_offset += (u64) val << 32; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_PP_SZ, &val); + if (rc) + return rc; + afu->pp_mmio_stride = val; + + return 0; +} + +static int read_afu_control(struct pci_dev *dev, struct ocxl_afu_config *afu) +{ + int pos; + u8 val8; + u16 val16; + + pos = find_dvsec_afu_ctrl(dev, afu->idx); + if (!pos) { + dev_err(&dev->dev, "Can't find AFU control DVSEC for AFU %d\n", + afu->idx); + return -ENODEV; + } + afu->dvsec_afu_control_pos = pos; + + pci_read_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_SUP, &val8); + afu->pasid_supported_log = EXTRACT_BITS(val8, 0, 4); + + pci_read_config_word(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_SUP, &val16); + afu->actag_supported = EXTRACT_BITS(val16, 0, 11); + return 0; +} + +static bool char_allowed(int c) +{ + /* + * Permitted Characters : Alphanumeric, hyphen, underscore, comma + */ + if ((c >= 0x30 && c <= 0x39) /* digits */ || + (c >= 0x41 && c <= 0x5A) /* upper case */ || + (c >= 0x61 && c <= 0x7A) /* lower case */ || + c == 0 /* NULL */ || + c == 0x2D /* - */ || + c == 0x5F /* _ */ || + c == 0x2C /* , */) + return true; + return false; +} + +static int validate_afu(struct pci_dev *dev, struct ocxl_afu_config *afu) +{ + int i; + + if (!afu->name[0]) { + dev_err(&dev->dev, "Empty AFU name\n"); + return -EINVAL; + } + for (i = 0; i < OCXL_TEMPL_NAME_LEN; i++) { + if (!char_allowed(afu->name[i])) { + dev_err(&dev->dev, + "Invalid character in AFU name\n"); + return -EINVAL; + } + } + + if (afu->global_mmio_bar != 0 && + afu->global_mmio_bar != 2 && + afu->global_mmio_bar != 4) { + dev_err(&dev->dev, "Invalid global MMIO bar number\n"); + return -EINVAL; + } + if (afu->pp_mmio_bar != 0 && + afu->pp_mmio_bar != 2 && + afu->pp_mmio_bar != 4) { + dev_err(&dev->dev, "Invalid per-process MMIO bar number\n"); + return -EINVAL; + } + return 0; +} + +int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn, + struct ocxl_afu_config *afu, u8 afu_idx) +{ + int rc; + u32 val32; + + /* + * First, we need to write the AFU idx for the AFU we want to + * access. + */ + WARN_ON((afu_idx & OCXL_DVSEC_AFU_IDX_MASK) != afu_idx); + afu->idx = afu_idx; + pci_write_config_byte(dev, + fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX, + afu->idx); + + rc = read_afu_name(dev, fn, afu); + if (rc) + return rc; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_AFU_VERSION, &val32); + if (rc) + return rc; + afu->version_major = EXTRACT_BITS(val32, 24, 31); + afu->version_minor = EXTRACT_BITS(val32, 16, 23); + afu->afuc_type = EXTRACT_BITS(val32, 14, 15); + afu->afum_type = EXTRACT_BITS(val32, 12, 13); + afu->profile = EXTRACT_BITS(val32, 0, 7); + + rc = read_afu_mmio(dev, fn, afu); + if (rc) + return rc; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MEM_SZ, &val32); + if (rc) + return rc; + afu->log_mem_size = EXTRACT_BITS(val32, 0, 7); + + rc = read_afu_control(dev, afu); + if (rc) + return rc; + + dev_dbg(&dev->dev, "AFU configuration:\n"); + dev_dbg(&dev->dev, " name = %s\n", afu->name); + dev_dbg(&dev->dev, " version = %d.%d\n", afu->version_major, + afu->version_minor); + dev_dbg(&dev->dev, " global mmio bar = %hhu\n", afu->global_mmio_bar); + dev_dbg(&dev->dev, " global mmio offset = %#llx\n", + afu->global_mmio_offset); + dev_dbg(&dev->dev, " global mmio size = %#x\n", afu->global_mmio_size); + dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar); + dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset); + dev_dbg(&dev->dev, " pp mmio stride = %#x\n", afu->pp_mmio_stride); + dev_dbg(&dev->dev, " mem size (log) = %hhu\n", afu->log_mem_size); + dev_dbg(&dev->dev, " pasid supported (log) = %u\n", + afu->pasid_supported_log); + dev_dbg(&dev->dev, " actag supported = %u\n", + afu->actag_supported); + + rc = validate_afu(dev, afu); + return rc; +} + +int ocxl_config_get_actag_info(struct pci_dev *dev, u16 *base, u16 *enabled, + u16 *supported) +{ + int rc; + + /* + * This is really a simple wrapper for the kernel API, to + * avoid an external driver using ocxl as a library to call + * platform-dependent code + */ + rc = pnv_ocxl_get_actag(dev, base, enabled, supported); + if (rc) { + dev_err(&dev->dev, "Can't get actag for device: %d\n", rc); + return rc; + } + return 0; +} + +void ocxl_config_set_afu_actag(struct pci_dev *dev, int pos, int actag_base, + int actag_count) +{ + u16 val; + + val = actag_count & OCXL_DVSEC_ACTAG_MASK; + pci_write_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_EN, val); + + val = actag_base & OCXL_DVSEC_ACTAG_MASK; + pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_BASE, val); +} + +int ocxl_config_get_pasid_info(struct pci_dev *dev, int *count) +{ + return pnv_ocxl_get_pasid_count(dev, count); +} + +void ocxl_config_set_afu_pasid(struct pci_dev *dev, int pos, int pasid_base, + u32 pasid_count_log) +{ + u8 val8; + u32 val32; + + val8 = pasid_count_log & OCXL_DVSEC_PASID_LOG_MASK; + pci_write_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_EN, val8); + + pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_BASE, + &val32); + val32 &= ~OCXL_DVSEC_PASID_MASK; + val32 |= pasid_base & OCXL_DVSEC_PASID_MASK; + pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_BASE, + val32); +} + +void ocxl_config_set_afu_state(struct pci_dev *dev, int pos, int enable) +{ + u8 val; + + pci_read_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_ENABLE, &val); + if (enable) + val |= 1; + else + val &= 0xFE; + pci_write_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_ENABLE, val); +} + +int ocxl_config_set_TL(struct pci_dev *dev, int tl_dvsec) +{ + u32 val; + __be32 *be32ptr; + u8 timers; + int i, rc; + long recv_cap; + char *recv_rate; + + /* + * Skip on function != 0, as the TL can only be defined on 0 + */ + if (PCI_FUNC(dev->devfn) != 0) + return 0; + + recv_rate = kzalloc(PNV_OCXL_TL_RATE_BUF_SIZE, GFP_KERNEL); + if (!recv_rate) + return -ENOMEM; + /* + * The spec defines 64 templates for messages in the + * Transaction Layer (TL). + * + * The host and device each support a subset, so we need to + * configure the transmitters on each side to send only + * templates the receiver understands, at a rate the receiver + * can process. Per the spec, template 0 must be supported by + * everybody. That's the template which has been used by the + * host and device so far. + * + * The sending rate limit must be set before the template is + * enabled. + */ + + /* + * Device -> host + */ + rc = pnv_ocxl_get_tl_cap(dev, &recv_cap, recv_rate, + PNV_OCXL_TL_RATE_BUF_SIZE); + if (rc) + goto out; + + for (i = 0; i < PNV_OCXL_TL_RATE_BUF_SIZE; i += 4) { + be32ptr = (__be32 *) &recv_rate[i]; + pci_write_config_dword(dev, + tl_dvsec + OCXL_DVSEC_TL_SEND_RATE + i, + be32_to_cpu(*be32ptr)); + } + val = recv_cap >> 32; + pci_write_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_SEND_CAP, val); + val = recv_cap & GENMASK(31, 0); + pci_write_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_SEND_CAP + 4, val); + + /* + * Host -> device + */ + for (i = 0; i < PNV_OCXL_TL_RATE_BUF_SIZE; i += 4) { + pci_read_config_dword(dev, + tl_dvsec + OCXL_DVSEC_TL_RECV_RATE + i, + &val); + be32ptr = (__be32 *) &recv_rate[i]; + *be32ptr = cpu_to_be32(val); + } + pci_read_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_RECV_CAP, &val); + recv_cap = (long) val << 32; + pci_read_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_RECV_CAP + 4, &val); + recv_cap |= val; + + rc = pnv_ocxl_set_tl_conf(dev, recv_cap, __pa(recv_rate), + PNV_OCXL_TL_RATE_BUF_SIZE); + if (rc) + goto out; + + /* + * Opencapi commands needing to be retried are classified per + * the TL in 2 groups: short and long commands. + * + * The short back off timer it not used for now. It will be + * for opencapi 4.0. + * + * The long back off timer is typically used when an AFU hits + * a page fault but the NPU is already processing one. So the + * AFU needs to wait before it can resubmit. Having a value + * too low doesn't break anything, but can generate extra + * traffic on the link. + * We set it to 1.6 us for now. It's shorter than, but in the + * same order of magnitude as the time spent to process a page + * fault. + */ + timers = 0x2 << 4; /* long timer = 1.6 us */ + pci_write_config_byte(dev, tl_dvsec + OCXL_DVSEC_TL_BACKOFF_TIMERS, + timers); + + rc = 0; +out: + kfree(recv_rate); + return rc; +} + +int ocxl_config_terminate_pasid(struct pci_dev *dev, int afu_control, int pasid) +{ + u32 val; + unsigned long timeout; + + pci_read_config_dword(dev, afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID, + &val); + if (EXTRACT_BIT(val, 20)) { + dev_err(&dev->dev, + "Can't terminate PASID %#x, previous termination didn't complete\n", + pasid); + return -EBUSY; + } + + val &= ~OCXL_DVSEC_PASID_MASK; + val |= pasid & OCXL_DVSEC_PASID_MASK; + val |= BIT(20); + pci_write_config_dword(dev, + afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID, + val); + + timeout = jiffies + (HZ * OCXL_CFG_TIMEOUT); + pci_read_config_dword(dev, afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID, + &val); + while (EXTRACT_BIT(val, 20)) { + if (time_after_eq(jiffies, timeout)) { + dev_err(&dev->dev, + "Timeout while waiting for AFU to terminate PASID %#x\n", + pasid); + return -EBUSY; + } + cpu_relax(); + pci_read_config_dword(dev, + afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID, + &val); + } + return 0; +} + +void ocxl_config_set_actag(struct pci_dev *dev, int func_dvsec, u32 tag_first, + u32 tag_count) +{ + u32 val; + + val = (tag_first & OCXL_DVSEC_ACTAG_MASK) << 16; + val |= tag_count & OCXL_DVSEC_ACTAG_MASK; + pci_write_config_dword(dev, func_dvsec + OCXL_DVSEC_FUNC_OFF_ACTAG, + val); +} diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c new file mode 100644 index 000000000000..b34b836f924c --- /dev/null +++ b/drivers/misc/ocxl/context.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include "ocxl_internal.h" + +struct ocxl_context *ocxl_context_alloc(void) +{ + return kzalloc(sizeof(struct ocxl_context), GFP_KERNEL); +} + +int ocxl_context_init(struct ocxl_context *ctx, struct ocxl_afu *afu, + struct address_space *mapping) +{ + int pasid; + + ctx->afu = afu; + mutex_lock(&afu->contexts_lock); + pasid = idr_alloc(&afu->contexts_idr, ctx, afu->pasid_base, + afu->pasid_base + afu->pasid_max, GFP_KERNEL); + if (pasid < 0) { + mutex_unlock(&afu->contexts_lock); + return pasid; + } + afu->pasid_count++; + mutex_unlock(&afu->contexts_lock); + + ctx->pasid = pasid; + ctx->status = OPENED; + mutex_init(&ctx->status_mutex); + ctx->mapping = mapping; + mutex_init(&ctx->mapping_lock); + init_waitqueue_head(&ctx->events_wq); + mutex_init(&ctx->xsl_error_lock); + /* + * Keep a reference on the AFU to make sure it's valid for the + * duration of the life of the context + */ + ocxl_afu_get(afu); + return 0; +} + +/* + * Callback for when a translation fault triggers an error + * data: a pointer to the context which triggered the fault + * addr: the address that triggered the error + * dsisr: the value of the PPC64 dsisr register + */ +static void xsl_fault_error(void *data, u64 addr, u64 dsisr) +{ + struct ocxl_context *ctx = (struct ocxl_context *) data; + + mutex_lock(&ctx->xsl_error_lock); + ctx->xsl_error.addr = addr; + ctx->xsl_error.dsisr = dsisr; + ctx->xsl_error.count++; + mutex_unlock(&ctx->xsl_error_lock); + + wake_up_all(&ctx->events_wq); +} + +int ocxl_context_attach(struct ocxl_context *ctx, u64 amr) +{ + int rc; + + mutex_lock(&ctx->status_mutex); + if (ctx->status != OPENED) { + rc = -EIO; + goto out; + } + + rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid, + current->mm->context.id, 0, amr, current->mm, + xsl_fault_error, ctx); + if (rc) + goto out; + + ctx->status = ATTACHED; +out: + mutex_unlock(&ctx->status_mutex); + return rc; +} + +static int map_pp_mmio(struct vm_area_struct *vma, unsigned long address, + u64 offset, struct ocxl_context *ctx) +{ + u64 pp_mmio_addr; + int pasid_off; + + if (offset >= ctx->afu->config.pp_mmio_stride) + return VM_FAULT_SIGBUS; + + mutex_lock(&ctx->status_mutex); + if (ctx->status != ATTACHED) { + mutex_unlock(&ctx->status_mutex); + pr_debug("%s: Context not attached, failing mmio mmap\n", + __func__); + return VM_FAULT_SIGBUS; + } + + pasid_off = ctx->pasid - ctx->afu->pasid_base; + pp_mmio_addr = ctx->afu->pp_mmio_start + + pasid_off * ctx->afu->config.pp_mmio_stride + + offset; + + vm_insert_pfn(vma, address, pp_mmio_addr >> PAGE_SHIFT); + mutex_unlock(&ctx->status_mutex); + return VM_FAULT_NOPAGE; +} + +static int ocxl_mmap_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct ocxl_context *ctx = vma->vm_file->private_data; + u64 offset; + int rc; + + offset = vmf->pgoff << PAGE_SHIFT; + pr_debug("%s: pasid %d address 0x%lx offset 0x%llx\n", __func__, + ctx->pasid, vmf->address, offset); + + rc = map_pp_mmio(vma, vmf->address, offset, ctx); + return rc; +} + +static const struct vm_operations_struct ocxl_vmops = { + .fault = ocxl_mmap_fault, +}; + +static int check_mmap_mmio(struct ocxl_context *ctx, + struct vm_area_struct *vma) +{ + if ((vma_pages(vma) + vma->vm_pgoff) > + (ctx->afu->config.pp_mmio_stride >> PAGE_SHIFT)) + return -EINVAL; + return 0; +} + +int ocxl_context_mmap(struct ocxl_context *ctx, struct vm_area_struct *vma) +{ + int rc; + + rc = check_mmap_mmio(ctx, vma); + if (rc) + return rc; + + vma->vm_flags |= VM_IO | VM_PFNMAP; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_ops = &ocxl_vmops; + return 0; +} + +int ocxl_context_detach(struct ocxl_context *ctx) +{ + struct pci_dev *dev; + int afu_control_pos; + enum ocxl_context_status status; + int rc; + + mutex_lock(&ctx->status_mutex); + status = ctx->status; + ctx->status = CLOSED; + mutex_unlock(&ctx->status_mutex); + if (status != ATTACHED) + return 0; + + dev = to_pci_dev(ctx->afu->fn->dev.parent); + afu_control_pos = ctx->afu->config.dvsec_afu_control_pos; + + mutex_lock(&ctx->afu->afu_control_lock); + rc = ocxl_config_terminate_pasid(dev, afu_control_pos, ctx->pasid); + mutex_unlock(&ctx->afu->afu_control_lock); + if (rc) { + /* + * If we timeout waiting for the AFU to terminate the + * pasid, then it's dangerous to clean up the Process + * Element entry in the SPA, as it may be referenced + * in the future by the AFU. In which case, we would + * checkstop because of an invalid PE access (FIR + * register 2, bit 42). So leave the PE + * defined. Caller shouldn't free the context so that + * PASID remains allocated. + * + * A link reset will be required to cleanup the AFU + * and the SPA. + */ + if (rc == -EBUSY) + return rc; + } + rc = ocxl_link_remove_pe(ctx->afu->fn->link, ctx->pasid); + if (rc) { + dev_warn(&ctx->afu->dev, + "Couldn't remove PE entry cleanly: %d\n", rc); + } + return 0; +} + +void ocxl_context_detach_all(struct ocxl_afu *afu) +{ + struct ocxl_context *ctx; + int tmp; + + mutex_lock(&afu->contexts_lock); + idr_for_each_entry(&afu->contexts_idr, ctx, tmp) { + ocxl_context_detach(ctx); + /* + * We are force detaching - remove any active mmio + * mappings so userspace cannot interfere with the + * card if it comes back. Easiest way to exercise + * this is to unbind and rebind the driver via sysfs + * while it is in use. + */ + mutex_lock(&ctx->mapping_lock); + if (ctx->mapping) + unmap_mapping_range(ctx->mapping, 0, 0, 1); + mutex_unlock(&ctx->mapping_lock); + } + mutex_unlock(&afu->contexts_lock); +} + +void ocxl_context_free(struct ocxl_context *ctx) +{ + mutex_lock(&ctx->afu->contexts_lock); + ctx->afu->pasid_count--; + idr_remove(&ctx->afu->contexts_idr, ctx->pasid); + mutex_unlock(&ctx->afu->contexts_lock); + + /* reference to the AFU taken in ocxl_context_init */ + ocxl_afu_put(ctx->afu); + kfree(ctx); +} diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c new file mode 100644 index 000000000000..6f0befda6a8a --- /dev/null +++ b/drivers/misc/ocxl/file.c @@ -0,0 +1,398 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include +#include +#include +#include +#include "ocxl_internal.h" + + +#define OCXL_NUM_MINORS 256 /* Total to reserve */ + +static dev_t ocxl_dev; +static struct class *ocxl_class; +static struct mutex minors_idr_lock; +static struct idr minors_idr; + +static struct ocxl_afu *find_and_get_afu(dev_t devno) +{ + struct ocxl_afu *afu; + int afu_minor; + + afu_minor = MINOR(devno); + /* + * We don't declare an RCU critical section here, as our AFU + * is protected by a reference counter on the device. By the time the + * minor number of a device is removed from the idr, the ref count of + * the device is already at 0, so no user API will access that AFU and + * this function can't return it. + */ + afu = idr_find(&minors_idr, afu_minor); + if (afu) + ocxl_afu_get(afu); + return afu; +} + +static int allocate_afu_minor(struct ocxl_afu *afu) +{ + int minor; + + mutex_lock(&minors_idr_lock); + minor = idr_alloc(&minors_idr, afu, 0, OCXL_NUM_MINORS, GFP_KERNEL); + mutex_unlock(&minors_idr_lock); + return minor; +} + +static void free_afu_minor(struct ocxl_afu *afu) +{ + mutex_lock(&minors_idr_lock); + idr_remove(&minors_idr, MINOR(afu->dev.devt)); + mutex_unlock(&minors_idr_lock); +} + +static int afu_open(struct inode *inode, struct file *file) +{ + struct ocxl_afu *afu; + struct ocxl_context *ctx; + int rc; + + pr_debug("%s for device %x\n", __func__, inode->i_rdev); + + afu = find_and_get_afu(inode->i_rdev); + if (!afu) + return -ENODEV; + + ctx = ocxl_context_alloc(); + if (!ctx) { + rc = -ENOMEM; + goto put_afu; + } + + rc = ocxl_context_init(ctx, afu, inode->i_mapping); + if (rc) + goto put_afu; + file->private_data = ctx; + ocxl_afu_put(afu); + return 0; + +put_afu: + ocxl_afu_put(afu); + return rc; +} + +static long afu_ioctl_attach(struct ocxl_context *ctx, + struct ocxl_ioctl_attach __user *uarg) +{ + struct ocxl_ioctl_attach arg; + u64 amr = 0; + int rc; + + pr_debug("%s for context %d\n", __func__, ctx->pasid); + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + /* Make sure reserved fields are not set for forward compatibility */ + if (arg.reserved1 || arg.reserved2 || arg.reserved3) + return -EINVAL; + + amr = arg.amr & mfspr(SPRN_UAMOR); + rc = ocxl_context_attach(ctx, amr); + return rc; +} + +#define CMD_STR(x) (x == OCXL_IOCTL_ATTACH ? "ATTACH" : \ + "UNKNOWN") + +static long afu_ioctl(struct file *file, unsigned int cmd, + unsigned long args) +{ + struct ocxl_context *ctx = file->private_data; + long rc; + + pr_debug("%s for context %d, command %s\n", __func__, ctx->pasid, + CMD_STR(cmd)); + + if (ctx->status == CLOSED) + return -EIO; + + switch (cmd) { + case OCXL_IOCTL_ATTACH: + rc = afu_ioctl_attach(ctx, + (struct ocxl_ioctl_attach __user *) args); + break; + + default: + rc = -EINVAL; + } + return rc; +} + +static long afu_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long args) +{ + return afu_ioctl(file, cmd, args); +} + +static int afu_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ocxl_context *ctx = file->private_data; + + pr_debug("%s for context %d\n", __func__, ctx->pasid); + return ocxl_context_mmap(ctx, vma); +} + +static bool has_xsl_error(struct ocxl_context *ctx) +{ + bool ret; + + mutex_lock(&ctx->xsl_error_lock); + ret = !!ctx->xsl_error.addr; + mutex_unlock(&ctx->xsl_error_lock); + + return ret; +} + +/* + * Are there any events pending on the AFU + * ctx: The AFU context + * Returns: true if there are events pending + */ +static bool afu_events_pending(struct ocxl_context *ctx) +{ + if (has_xsl_error(ctx)) + return true; + return false; +} + +static unsigned int afu_poll(struct file *file, struct poll_table_struct *wait) +{ + struct ocxl_context *ctx = file->private_data; + unsigned int mask = 0; + bool closed; + + pr_debug("%s for context %d\n", __func__, ctx->pasid); + + poll_wait(file, &ctx->events_wq, wait); + + mutex_lock(&ctx->status_mutex); + closed = (ctx->status == CLOSED); + mutex_unlock(&ctx->status_mutex); + + if (afu_events_pending(ctx)) + mask = POLLIN | POLLRDNORM; + else if (closed) + mask = POLLERR; + + return mask; +} + +/* + * Populate the supplied buffer with a single XSL error + * ctx: The AFU context to report the error from + * header: the event header to populate + * buf: The buffer to write the body into (should be at least + * AFU_EVENT_BODY_XSL_ERROR_SIZE) + * Return: the amount of buffer that was populated + */ +static ssize_t append_xsl_error(struct ocxl_context *ctx, + struct ocxl_kernel_event_header *header, + char __user *buf) +{ + struct ocxl_kernel_event_xsl_fault_error body; + + memset(&body, 0, sizeof(body)); + + mutex_lock(&ctx->xsl_error_lock); + if (!ctx->xsl_error.addr) { + mutex_unlock(&ctx->xsl_error_lock); + return 0; + } + + body.addr = ctx->xsl_error.addr; + body.dsisr = ctx->xsl_error.dsisr; + body.count = ctx->xsl_error.count; + + ctx->xsl_error.addr = 0; + ctx->xsl_error.dsisr = 0; + ctx->xsl_error.count = 0; + + mutex_unlock(&ctx->xsl_error_lock); + + header->type = OCXL_AFU_EVENT_XSL_FAULT_ERROR; + + if (copy_to_user(buf, &body, sizeof(body))) + return -EFAULT; + + return sizeof(body); +} + +#define AFU_EVENT_BODY_MAX_SIZE sizeof(struct ocxl_kernel_event_xsl_fault_error) + +/* + * Reports events on the AFU + * Format: + * Header (struct ocxl_kernel_event_header) + * Body (struct ocxl_kernel_event_*) + * Header... + */ +static ssize_t afu_read(struct file *file, char __user *buf, size_t count, + loff_t *off) +{ + struct ocxl_context *ctx = file->private_data; + struct ocxl_kernel_event_header header; + ssize_t rc; + size_t used = 0; + DEFINE_WAIT(event_wait); + + memset(&header, 0, sizeof(header)); + + /* Require offset to be 0 */ + if (*off != 0) + return -EINVAL; + + if (count < (sizeof(struct ocxl_kernel_event_header) + + AFU_EVENT_BODY_MAX_SIZE)) + return -EINVAL; + + for (;;) { + prepare_to_wait(&ctx->events_wq, &event_wait, + TASK_INTERRUPTIBLE); + + if (afu_events_pending(ctx)) + break; + + if (ctx->status == CLOSED) + break; + + if (file->f_flags & O_NONBLOCK) { + finish_wait(&ctx->events_wq, &event_wait); + return -EAGAIN; + } + + if (signal_pending(current)) { + finish_wait(&ctx->events_wq, &event_wait); + return -ERESTARTSYS; + } + + schedule(); + } + + finish_wait(&ctx->events_wq, &event_wait); + + if (has_xsl_error(ctx)) { + used = append_xsl_error(ctx, &header, buf + sizeof(header)); + if (used < 0) + return used; + } + + if (!afu_events_pending(ctx)) + header.flags |= OCXL_KERNEL_EVENT_FLAG_LAST; + + if (copy_to_user(buf, &header, sizeof(header))) + return -EFAULT; + + used += sizeof(header); + + rc = (ssize_t) used; + return rc; +} + +static int afu_release(struct inode *inode, struct file *file) +{ + struct ocxl_context *ctx = file->private_data; + int rc; + + pr_debug("%s for device %x\n", __func__, inode->i_rdev); + rc = ocxl_context_detach(ctx); + mutex_lock(&ctx->mapping_lock); + ctx->mapping = NULL; + mutex_unlock(&ctx->mapping_lock); + wake_up_all(&ctx->events_wq); + if (rc != -EBUSY) + ocxl_context_free(ctx); + return 0; +} + +static const struct file_operations ocxl_afu_fops = { + .owner = THIS_MODULE, + .open = afu_open, + .unlocked_ioctl = afu_ioctl, + .compat_ioctl = afu_compat_ioctl, + .mmap = afu_mmap, + .poll = afu_poll, + .read = afu_read, + .release = afu_release, +}; + +int ocxl_create_cdev(struct ocxl_afu *afu) +{ + int rc; + + cdev_init(&afu->cdev, &ocxl_afu_fops); + rc = cdev_add(&afu->cdev, afu->dev.devt, 1); + if (rc) { + dev_err(&afu->dev, "Unable to add afu char device: %d\n", rc); + return rc; + } + return 0; +} + +void ocxl_destroy_cdev(struct ocxl_afu *afu) +{ + cdev_del(&afu->cdev); +} + +int ocxl_register_afu(struct ocxl_afu *afu) +{ + int minor; + + minor = allocate_afu_minor(afu); + if (minor < 0) + return minor; + afu->dev.devt = MKDEV(MAJOR(ocxl_dev), minor); + afu->dev.class = ocxl_class; + return device_register(&afu->dev); +} + +void ocxl_unregister_afu(struct ocxl_afu *afu) +{ + free_afu_minor(afu); +} + +static char *ocxl_devnode(struct device *dev, umode_t *mode) +{ + return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev)); +} + +int ocxl_file_init(void) +{ + int rc; + + mutex_init(&minors_idr_lock); + idr_init(&minors_idr); + + rc = alloc_chrdev_region(&ocxl_dev, 0, OCXL_NUM_MINORS, "ocxl"); + if (rc) { + pr_err("Unable to allocate ocxl major number: %d\n", rc); + return rc; + } + + ocxl_class = class_create(THIS_MODULE, "ocxl"); + if (IS_ERR(ocxl_class)) { + pr_err("Unable to create ocxl class\n"); + unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); + return PTR_ERR(ocxl_class); + } + + ocxl_class->devnode = ocxl_devnode; + return 0; +} + +void ocxl_file_exit(void) +{ + class_destroy(ocxl_class); + unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); + idr_destroy(&minors_idr); +} diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c new file mode 100644 index 000000000000..64d7a98c904a --- /dev/null +++ b/drivers/misc/ocxl/link.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include +#include +#include +#include +#include "ocxl_internal.h" + + +#define SPA_PASID_BITS 15 +#define SPA_PASID_MAX ((1 << SPA_PASID_BITS) - 1) +#define SPA_PE_MASK SPA_PASID_MAX +#define SPA_SPA_SIZE_LOG 22 /* Each SPA is 4 Mb */ + +#define SPA_CFG_SF (1ull << (63-0)) +#define SPA_CFG_TA (1ull << (63-1)) +#define SPA_CFG_HV (1ull << (63-3)) +#define SPA_CFG_UV (1ull << (63-4)) +#define SPA_CFG_XLAT_hpt (0ull << (63-6)) /* Hashed page table (HPT) mode */ +#define SPA_CFG_XLAT_roh (2ull << (63-6)) /* Radix on HPT mode */ +#define SPA_CFG_XLAT_ror (3ull << (63-6)) /* Radix on Radix mode */ +#define SPA_CFG_PR (1ull << (63-49)) +#define SPA_CFG_TC (1ull << (63-54)) +#define SPA_CFG_DR (1ull << (63-59)) + +#define SPA_XSL_TF (1ull << (63-3)) /* Translation fault */ +#define SPA_XSL_S (1ull << (63-38)) /* Store operation */ + +#define SPA_PE_VALID 0x80000000 + + +struct pe_data { + struct mm_struct *mm; + /* callback to trigger when a translation fault occurs */ + void (*xsl_err_cb)(void *data, u64 addr, u64 dsisr); + /* opaque pointer to be passed to the above callback */ + void *xsl_err_data; + struct rcu_head rcu; +}; + +struct spa { + struct ocxl_process_element *spa_mem; + int spa_order; + struct mutex spa_lock; + struct radix_tree_root pe_tree; /* Maps PE handles to pe_data */ + char *irq_name; + int virq; + void __iomem *reg_dsisr; + void __iomem *reg_dar; + void __iomem *reg_tfc; + void __iomem *reg_pe_handle; + /* + * The following field are used by the memory fault + * interrupt handler. We can only have one interrupt at a + * time. The NPU won't raise another interrupt until the + * previous one has been ack'd by writing to the TFC register + */ + struct xsl_fault { + struct work_struct fault_work; + u64 pe; + u64 dsisr; + u64 dar; + struct pe_data pe_data; + } xsl_fault; +}; + +/* + * A opencapi link can be used be by several PCI functions. We have + * one link per device slot. + * + * A linked list of opencapi links should suffice, as there's a + * limited number of opencapi slots on a system and lookup is only + * done when the device is probed + */ +struct link { + struct list_head list; + struct kref ref; + int domain; + int bus; + int dev; + atomic_t irq_available; + struct spa *spa; + void *platform_data; +}; +static struct list_head links_list = LIST_HEAD_INIT(links_list); +static DEFINE_MUTEX(links_list_lock); + +enum xsl_response { + CONTINUE, + ADDRESS_ERROR, + RESTART, +}; + + +static void read_irq(struct spa *spa, u64 *dsisr, u64 *dar, u64 *pe) +{ + u64 reg; + + *dsisr = in_be64(spa->reg_dsisr); + *dar = in_be64(spa->reg_dar); + reg = in_be64(spa->reg_pe_handle); + *pe = reg & SPA_PE_MASK; +} + +static void ack_irq(struct spa *spa, enum xsl_response r) +{ + u64 reg = 0; + + /* continue is not supported */ + if (r == RESTART) + reg = PPC_BIT(31); + else if (r == ADDRESS_ERROR) + reg = PPC_BIT(30); + else + WARN(1, "Invalid irq response %d\n", r); + + if (reg) + out_be64(spa->reg_tfc, reg); +} + +static void xsl_fault_handler_bh(struct work_struct *fault_work) +{ + unsigned int flt = 0; + unsigned long access, flags, inv_flags = 0; + enum xsl_response r; + struct xsl_fault *fault = container_of(fault_work, struct xsl_fault, + fault_work); + struct spa *spa = container_of(fault, struct spa, xsl_fault); + + int rc; + + /* + * We need to release a reference on the mm whenever exiting this + * function (taken in the memory fault interrupt handler) + */ + rc = copro_handle_mm_fault(fault->pe_data.mm, fault->dar, fault->dsisr, + &flt); + if (rc) { + pr_debug("copro_handle_mm_fault failed: %d\n", rc); + if (fault->pe_data.xsl_err_cb) { + fault->pe_data.xsl_err_cb( + fault->pe_data.xsl_err_data, + fault->dar, fault->dsisr); + } + r = ADDRESS_ERROR; + goto ack; + } + + if (!radix_enabled()) { + /* + * update_mmu_cache() will not have loaded the hash + * since current->trap is not a 0x400 or 0x300, so + * just call hash_page_mm() here. + */ + access = _PAGE_PRESENT | _PAGE_READ; + if (fault->dsisr & SPA_XSL_S) + access |= _PAGE_WRITE; + + if (REGION_ID(fault->dar) != USER_REGION_ID) + access |= _PAGE_PRIVILEGED; + + local_irq_save(flags); + hash_page_mm(fault->pe_data.mm, fault->dar, access, 0x300, + inv_flags); + local_irq_restore(flags); + } + r = RESTART; +ack: + mmdrop(fault->pe_data.mm); + ack_irq(spa, r); +} + +static irqreturn_t xsl_fault_handler(int irq, void *data) +{ + struct link *link = (struct link *) data; + struct spa *spa = link->spa; + u64 dsisr, dar, pe_handle; + struct pe_data *pe_data; + struct ocxl_process_element *pe; + int lpid, pid, tid; + + read_irq(spa, &dsisr, &dar, &pe_handle); + + WARN_ON(pe_handle > SPA_PE_MASK); + pe = spa->spa_mem + pe_handle; + lpid = be32_to_cpu(pe->lpid); + pid = be32_to_cpu(pe->pid); + tid = be32_to_cpu(pe->tid); + /* We could be reading all null values here if the PE is being + * removed while an interrupt kicks in. It's not supposed to + * happen if the driver notified the AFU to terminate the + * PASID, and the AFU waited for pending operations before + * acknowledging. But even if it happens, we won't find a + * memory context below and fail silently, so it should be ok. + */ + if (!(dsisr & SPA_XSL_TF)) { + WARN(1, "Invalid xsl interrupt fault register %#llx\n", dsisr); + ack_irq(spa, ADDRESS_ERROR); + return IRQ_HANDLED; + } + + rcu_read_lock(); + pe_data = radix_tree_lookup(&spa->pe_tree, pe_handle); + if (!pe_data) { + /* + * Could only happen if the driver didn't notify the + * AFU about PASID termination before removing the PE, + * or the AFU didn't wait for all memory access to + * have completed. + * + * Either way, we fail early, but we shouldn't log an + * error message, as it is a valid (if unexpected) + * scenario + */ + rcu_read_unlock(); + pr_debug("Unknown mm context for xsl interrupt\n"); + ack_irq(spa, ADDRESS_ERROR); + return IRQ_HANDLED; + } + WARN_ON(pe_data->mm->context.id != pid); + + spa->xsl_fault.pe = pe_handle; + spa->xsl_fault.dar = dar; + spa->xsl_fault.dsisr = dsisr; + spa->xsl_fault.pe_data = *pe_data; + mmgrab(pe_data->mm); /* mm count is released by bottom half */ + + rcu_read_unlock(); + schedule_work(&spa->xsl_fault.fault_work); + return IRQ_HANDLED; +} + +static void unmap_irq_registers(struct spa *spa) +{ + pnv_ocxl_unmap_xsl_regs(spa->reg_dsisr, spa->reg_dar, spa->reg_tfc, + spa->reg_pe_handle); +} + +static int map_irq_registers(struct pci_dev *dev, struct spa *spa) +{ + return pnv_ocxl_map_xsl_regs(dev, &spa->reg_dsisr, &spa->reg_dar, + &spa->reg_tfc, &spa->reg_pe_handle); +} + +static int setup_xsl_irq(struct pci_dev *dev, struct link *link) +{ + struct spa *spa = link->spa; + int rc; + int hwirq; + + rc = pnv_ocxl_get_xsl_irq(dev, &hwirq); + if (rc) + return rc; + + rc = map_irq_registers(dev, spa); + if (rc) + return rc; + + spa->irq_name = kasprintf(GFP_KERNEL, "ocxl-xsl-%x-%x-%x", + link->domain, link->bus, link->dev); + if (!spa->irq_name) { + unmap_irq_registers(spa); + dev_err(&dev->dev, "Can't allocate name for xsl interrupt\n"); + return -ENOMEM; + } + /* + * At some point, we'll need to look into allowing a higher + * number of interrupts. Could we have an IRQ domain per link? + */ + spa->virq = irq_create_mapping(NULL, hwirq); + if (!spa->virq) { + kfree(spa->irq_name); + unmap_irq_registers(spa); + dev_err(&dev->dev, + "irq_create_mapping failed for translation interrupt\n"); + return -EINVAL; + } + + dev_dbg(&dev->dev, "hwirq %d mapped to virq %d\n", hwirq, spa->virq); + + rc = request_irq(spa->virq, xsl_fault_handler, 0, spa->irq_name, + link); + if (rc) { + irq_dispose_mapping(spa->virq); + kfree(spa->irq_name); + unmap_irq_registers(spa); + dev_err(&dev->dev, + "request_irq failed for translation interrupt: %d\n", + rc); + return -EINVAL; + } + return 0; +} + +static void release_xsl_irq(struct link *link) +{ + struct spa *spa = link->spa; + + if (spa->virq) { + free_irq(spa->virq, link); + irq_dispose_mapping(spa->virq); + } + kfree(spa->irq_name); + unmap_irq_registers(spa); +} + +static int alloc_spa(struct pci_dev *dev, struct link *link) +{ + struct spa *spa; + + spa = kzalloc(sizeof(struct spa), GFP_KERNEL); + if (!spa) + return -ENOMEM; + + mutex_init(&spa->spa_lock); + INIT_RADIX_TREE(&spa->pe_tree, GFP_KERNEL); + INIT_WORK(&spa->xsl_fault.fault_work, xsl_fault_handler_bh); + + spa->spa_order = SPA_SPA_SIZE_LOG - PAGE_SHIFT; + spa->spa_mem = (struct ocxl_process_element *) + __get_free_pages(GFP_KERNEL | __GFP_ZERO, spa->spa_order); + if (!spa->spa_mem) { + dev_err(&dev->dev, "Can't allocate Shared Process Area\n"); + kfree(spa); + return -ENOMEM; + } + pr_debug("Allocated SPA for %x:%x:%x at %p\n", link->domain, link->bus, + link->dev, spa->spa_mem); + + link->spa = spa; + return 0; +} + +static void free_spa(struct link *link) +{ + struct spa *spa = link->spa; + + pr_debug("Freeing SPA for %x:%x:%x\n", link->domain, link->bus, + link->dev); + + if (spa && spa->spa_mem) { + free_pages((unsigned long) spa->spa_mem, spa->spa_order); + kfree(spa); + link->spa = NULL; + } +} + +static int alloc_link(struct pci_dev *dev, int PE_mask, struct link **out_link) +{ + struct link *link; + int rc; + + link = kzalloc(sizeof(struct link), GFP_KERNEL); + if (!link) + return -ENOMEM; + + kref_init(&link->ref); + link->domain = pci_domain_nr(dev->bus); + link->bus = dev->bus->number; + link->dev = PCI_SLOT(dev->devfn); + atomic_set(&link->irq_available, MAX_IRQ_PER_LINK); + + rc = alloc_spa(dev, link); + if (rc) + goto err_free; + + rc = setup_xsl_irq(dev, link); + if (rc) + goto err_spa; + + /* platform specific hook */ + rc = pnv_ocxl_spa_setup(dev, link->spa->spa_mem, PE_mask, + &link->platform_data); + if (rc) + goto err_xsl_irq; + + *out_link = link; + return 0; + +err_xsl_irq: + release_xsl_irq(link); +err_spa: + free_spa(link); +err_free: + kfree(link); + return rc; +} + +static void free_link(struct link *link) +{ + release_xsl_irq(link); + free_spa(link); + kfree(link); +} + +int ocxl_link_setup(struct pci_dev *dev, int PE_mask, void **link_handle) +{ + int rc = 0; + struct link *link; + + mutex_lock(&links_list_lock); + list_for_each_entry(link, &links_list, list) { + /* The functions of a device all share the same link */ + if (link->domain == pci_domain_nr(dev->bus) && + link->bus == dev->bus->number && + link->dev == PCI_SLOT(dev->devfn)) { + kref_get(&link->ref); + *link_handle = link; + goto unlock; + } + } + rc = alloc_link(dev, PE_mask, &link); + if (rc) + goto unlock; + + list_add(&link->list, &links_list); + *link_handle = link; +unlock: + mutex_unlock(&links_list_lock); + return rc; +} + +static void release_xsl(struct kref *ref) +{ + struct link *link = container_of(ref, struct link, ref); + + list_del(&link->list); + /* call platform code before releasing data */ + pnv_ocxl_spa_release(link->platform_data); + free_link(link); +} + +void ocxl_link_release(struct pci_dev *dev, void *link_handle) +{ + struct link *link = (struct link *) link_handle; + + mutex_lock(&links_list_lock); + kref_put(&link->ref, release_xsl); + mutex_unlock(&links_list_lock); +} + +static u64 calculate_cfg_state(bool kernel) +{ + u64 state; + + state = SPA_CFG_DR; + if (mfspr(SPRN_LPCR) & LPCR_TC) + state |= SPA_CFG_TC; + if (radix_enabled()) + state |= SPA_CFG_XLAT_ror; + else + state |= SPA_CFG_XLAT_hpt; + state |= SPA_CFG_HV; + if (kernel) { + if (mfmsr() & MSR_SF) + state |= SPA_CFG_SF; + } else { + state |= SPA_CFG_PR; + if (!test_tsk_thread_flag(current, TIF_32BIT)) + state |= SPA_CFG_SF; + } + return state; +} + +int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr, + u64 amr, struct mm_struct *mm, + void (*xsl_err_cb)(void *data, u64 addr, u64 dsisr), + void *xsl_err_data) +{ + struct link *link = (struct link *) link_handle; + struct spa *spa = link->spa; + struct ocxl_process_element *pe; + int pe_handle, rc = 0; + struct pe_data *pe_data; + + BUILD_BUG_ON(sizeof(struct ocxl_process_element) != 128); + if (pasid > SPA_PASID_MAX) + return -EINVAL; + + mutex_lock(&spa->spa_lock); + pe_handle = pasid & SPA_PE_MASK; + pe = spa->spa_mem + pe_handle; + + if (pe->software_state) { + rc = -EBUSY; + goto unlock; + } + + pe_data = kmalloc(sizeof(*pe_data), GFP_KERNEL); + if (!pe_data) { + rc = -ENOMEM; + goto unlock; + } + + pe_data->mm = mm; + pe_data->xsl_err_cb = xsl_err_cb; + pe_data->xsl_err_data = xsl_err_data; + + memset(pe, 0, sizeof(struct ocxl_process_element)); + pe->config_state = cpu_to_be64(calculate_cfg_state(pidr == 0)); + pe->lpid = cpu_to_be32(mfspr(SPRN_LPID)); + pe->pid = cpu_to_be32(pidr); + pe->tid = cpu_to_be32(tidr); + pe->amr = cpu_to_be64(amr); + pe->software_state = cpu_to_be32(SPA_PE_VALID); + + mm_context_add_copro(mm); + /* + * Barrier is to make sure PE is visible in the SPA before it + * is used by the device. It also helps with the global TLBI + * invalidation + */ + mb(); + radix_tree_insert(&spa->pe_tree, pe_handle, pe_data); + + /* + * The mm must stay valid for as long as the device uses it. We + * lower the count when the context is removed from the SPA. + * + * We grab mm_count (and not mm_users), as we don't want to + * end up in a circular dependency if a process mmaps its + * mmio, therefore incrementing the file ref count when + * calling mmap(), and forgets to unmap before exiting. In + * that scenario, when the kernel handles the death of the + * process, the file is not cleaned because unmap was not + * called, and the mm wouldn't be freed because we would still + * have a reference on mm_users. Incrementing mm_count solves + * the problem. + */ + mmgrab(mm); +unlock: + mutex_unlock(&spa->spa_lock); + return rc; +} + +int ocxl_link_remove_pe(void *link_handle, int pasid) +{ + struct link *link = (struct link *) link_handle; + struct spa *spa = link->spa; + struct ocxl_process_element *pe; + struct pe_data *pe_data; + int pe_handle, rc; + + if (pasid > SPA_PASID_MAX) + return -EINVAL; + + /* + * About synchronization with our memory fault handler: + * + * Before removing the PE, the driver is supposed to have + * notified the AFU, which should have cleaned up and make + * sure the PASID is no longer in use, including pending + * interrupts. However, there's no way to be sure... + * + * We clear the PE and remove the context from our radix + * tree. From that point on, any new interrupt for that + * context will fail silently, which is ok. As mentioned + * above, that's not expected, but it could happen if the + * driver or AFU didn't do the right thing. + * + * There could still be a bottom half running, but we don't + * need to wait/flush, as it is managing a reference count on + * the mm it reads from the radix tree. + */ + pe_handle = pasid & SPA_PE_MASK; + pe = spa->spa_mem + pe_handle; + + mutex_lock(&spa->spa_lock); + + if (!(be32_to_cpu(pe->software_state) & SPA_PE_VALID)) { + rc = -EINVAL; + goto unlock; + } + + memset(pe, 0, sizeof(struct ocxl_process_element)); + /* + * The barrier makes sure the PE is removed from the SPA + * before we clear the NPU context cache below, so that the + * old PE cannot be reloaded erroneously. + */ + mb(); + + /* + * hook to platform code + * On powerpc, the entry needs to be cleared from the context + * cache of the NPU. + */ + rc = pnv_ocxl_spa_remove_pe(link->platform_data, pe_handle); + WARN_ON(rc); + + pe_data = radix_tree_delete(&spa->pe_tree, pe_handle); + if (!pe_data) { + WARN(1, "Couldn't find pe data when removing PE\n"); + } else { + mm_context_remove_copro(pe_data->mm); + mmdrop(pe_data->mm); + kfree_rcu(pe_data, rcu); + } +unlock: + mutex_unlock(&spa->spa_lock); + return rc; +} diff --git a/drivers/misc/ocxl/main.c b/drivers/misc/ocxl/main.c new file mode 100644 index 000000000000..7210d9e059be --- /dev/null +++ b/drivers/misc/ocxl/main.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include +#include "ocxl_internal.h" + +static int __init init_ocxl(void) +{ + int rc = 0; + + rc = ocxl_file_init(); + if (rc) + return rc; + + rc = pci_register_driver(&ocxl_pci_driver); + if (rc) { + ocxl_file_exit(); + return rc; + } + return 0; +} + +static void exit_ocxl(void) +{ + pci_unregister_driver(&ocxl_pci_driver); + ocxl_file_exit(); +} + +module_init(init_ocxl); +module_exit(exit_ocxl); + +MODULE_DESCRIPTION("Open Coherent Accelerator"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h new file mode 100644 index 000000000000..04fc160c7bd5 --- /dev/null +++ b/drivers/misc/ocxl/ocxl_internal.h @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#ifndef _OCXL_INTERNAL_H_ +#define _OCXL_INTERNAL_H_ + +#include +#include +#include + +#define OCXL_AFU_NAME_SZ (24+1) /* add 1 for NULL termination */ +#define MAX_IRQ_PER_LINK 2000 +#define MAX_IRQ_PER_CONTEXT MAX_IRQ_PER_LINK + +#define to_ocxl_function(d) container_of(d, struct ocxl_fn, dev) +#define to_ocxl_afu(d) container_of(d, struct ocxl_afu, dev) + +extern struct pci_driver ocxl_pci_driver; + +/* + * The following 2 structures are a fairly generic way of representing + * the configuration data for a function and AFU, as read from the + * configuration space. + */ +struct ocxl_afu_config { + u8 idx; + int dvsec_afu_control_pos; + char name[OCXL_AFU_NAME_SZ]; + u8 version_major; + u8 version_minor; + u8 afuc_type; + u8 afum_type; + u8 profile; + u8 global_mmio_bar; + u64 global_mmio_offset; + u32 global_mmio_size; + u8 pp_mmio_bar; + u64 pp_mmio_offset; + u32 pp_mmio_stride; + u8 log_mem_size; + u8 pasid_supported_log; + u16 actag_supported; +}; + +struct ocxl_fn_config { + int dvsec_tl_pos; + int dvsec_function_pos; + int dvsec_afu_info_pos; + s8 max_pasid_log; + s8 max_afu_index; +}; + +struct ocxl_fn { + struct device dev; + int bar_used[3]; + struct ocxl_fn_config config; + struct list_head afu_list; + int pasid_base; + int actag_base; + int actag_enabled; + int actag_supported; + struct list_head pasid_list; + struct list_head actag_list; + void *link; +}; + +struct ocxl_afu { + struct ocxl_fn *fn; + struct list_head list; + struct device dev; + struct cdev cdev; + struct ocxl_afu_config config; + int pasid_base; + int pasid_count; /* opened contexts */ + int pasid_max; /* maximum number of contexts */ + int actag_base; + int actag_enabled; + struct mutex contexts_lock; + struct idr contexts_idr; + struct mutex afu_control_lock; + u64 global_mmio_start; + u64 irq_base_offset; + void __iomem *global_mmio_ptr; + u64 pp_mmio_start; + struct bin_attribute attr_global_mmio; +}; + +enum ocxl_context_status { + CLOSED, + OPENED, + ATTACHED, +}; + +// Contains metadata about a translation fault +struct ocxl_xsl_error { + u64 addr; // The address that triggered the fault + u64 dsisr; // the value of the dsisr register + u64 count; // The number of times this fault has been triggered +}; + +struct ocxl_context { + struct ocxl_afu *afu; + int pasid; + struct mutex status_mutex; + enum ocxl_context_status status; + struct address_space *mapping; + struct mutex mapping_lock; + wait_queue_head_t events_wq; + struct mutex xsl_error_lock; + struct ocxl_xsl_error xsl_error; + struct mutex irq_lock; + struct idr irq_idr; +}; + +struct ocxl_process_element { + __be64 config_state; + __be32 reserved1[11]; + __be32 lpid; + __be32 tid; + __be32 pid; + __be32 reserved2[10]; + __be64 amr; + __be32 reserved3[3]; + __be32 software_state; +}; + + +extern struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu); +extern void ocxl_afu_put(struct ocxl_afu *afu); + +extern int ocxl_create_cdev(struct ocxl_afu *afu); +extern void ocxl_destroy_cdev(struct ocxl_afu *afu); +extern int ocxl_register_afu(struct ocxl_afu *afu); +extern void ocxl_unregister_afu(struct ocxl_afu *afu); + +extern int ocxl_file_init(void); +extern void ocxl_file_exit(void); + +extern int ocxl_config_read_function(struct pci_dev *dev, + struct ocxl_fn_config *fn); + +extern int ocxl_config_check_afu_index(struct pci_dev *dev, + struct ocxl_fn_config *fn, int afu_idx); +extern int ocxl_config_read_afu(struct pci_dev *dev, + struct ocxl_fn_config *fn, + struct ocxl_afu_config *afu, + u8 afu_idx); +extern int ocxl_config_get_pasid_info(struct pci_dev *dev, int *count); +extern void ocxl_config_set_afu_pasid(struct pci_dev *dev, + int afu_control, + int pasid_base, u32 pasid_count_log); +extern int ocxl_config_get_actag_info(struct pci_dev *dev, + u16 *base, u16 *enabled, u16 *supported); +extern void ocxl_config_set_actag(struct pci_dev *dev, int func_dvsec, + u32 tag_first, u32 tag_count); +extern void ocxl_config_set_afu_actag(struct pci_dev *dev, int afu_control, + int actag_base, int actag_count); +extern void ocxl_config_set_afu_state(struct pci_dev *dev, int afu_control, + int enable); +extern int ocxl_config_set_TL(struct pci_dev *dev, int tl_dvsec); +extern int ocxl_config_terminate_pasid(struct pci_dev *dev, int afu_control, + int pasid); + +extern int ocxl_link_setup(struct pci_dev *dev, int PE_mask, + void **link_handle); +extern void ocxl_link_release(struct pci_dev *dev, void *link_handle); +extern int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr, + u64 amr, struct mm_struct *mm, + void (*xsl_err_cb)(void *data, u64 addr, u64 dsisr), + void *xsl_err_data); +extern int ocxl_link_remove_pe(void *link_handle, int pasid); +extern int ocxl_link_irq_alloc(void *link_handle, int *hw_irq, + u64 *addr); +extern void ocxl_link_free_irq(void *link_handle, int hw_irq); + +extern int ocxl_pasid_afu_alloc(struct ocxl_fn *fn, u32 size); +extern void ocxl_pasid_afu_free(struct ocxl_fn *fn, u32 start, u32 size); +extern int ocxl_actag_afu_alloc(struct ocxl_fn *fn, u32 size); +extern void ocxl_actag_afu_free(struct ocxl_fn *fn, u32 start, u32 size); + +extern struct ocxl_context *ocxl_context_alloc(void); +extern int ocxl_context_init(struct ocxl_context *ctx, struct ocxl_afu *afu, + struct address_space *mapping); +extern int ocxl_context_attach(struct ocxl_context *ctx, u64 amr); +extern int ocxl_context_mmap(struct ocxl_context *ctx, + struct vm_area_struct *vma); +extern int ocxl_context_detach(struct ocxl_context *ctx); +extern void ocxl_context_detach_all(struct ocxl_afu *afu); +extern void ocxl_context_free(struct ocxl_context *ctx); + +extern int ocxl_sysfs_add_afu(struct ocxl_afu *afu); +extern void ocxl_sysfs_remove_afu(struct ocxl_afu *afu); + +#endif /* _OCXL_INTERNAL_H_ */ diff --git a/drivers/misc/ocxl/pasid.c b/drivers/misc/ocxl/pasid.c new file mode 100644 index 000000000000..d14cb56e6920 --- /dev/null +++ b/drivers/misc/ocxl/pasid.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include "ocxl_internal.h" + + +struct id_range { + struct list_head list; + u32 start; + u32 end; +}; + +#ifdef DEBUG +static void dump_list(struct list_head *head, char *type_str) +{ + struct id_range *cur; + + pr_debug("%s ranges allocated:\n", type_str); + list_for_each_entry(cur, head, list) { + pr_debug("Range %d->%d\n", cur->start, cur->end); + } +} +#endif + +static int range_alloc(struct list_head *head, u32 size, int max_id, + char *type_str) +{ + struct list_head *pos; + struct id_range *cur, *new; + int rc, last_end; + + new = kmalloc(sizeof(struct id_range), GFP_KERNEL); + if (!new) + return -ENOMEM; + + pos = head; + last_end = -1; + list_for_each_entry(cur, head, list) { + if ((cur->start - last_end) > size) + break; + last_end = cur->end; + pos = &cur->list; + } + + new->start = last_end + 1; + new->end = new->start + size - 1; + + if (new->end > max_id) { + kfree(new); + rc = -ENOSPC; + } else { + list_add(&new->list, pos); + rc = new->start; + } + +#ifdef DEBUG + dump_list(head, type_str); +#endif + return rc; +} + +static void range_free(struct list_head *head, u32 start, u32 size, + char *type_str) +{ + bool found = false; + struct id_range *cur, *tmp; + + list_for_each_entry_safe(cur, tmp, head, list) { + if (cur->start == start && cur->end == (start + size - 1)) { + found = true; + list_del(&cur->list); + kfree(cur); + break; + } + } + WARN_ON(!found); +#ifdef DEBUG + dump_list(head, type_str); +#endif +} + +int ocxl_pasid_afu_alloc(struct ocxl_fn *fn, u32 size) +{ + int max_pasid; + + if (fn->config.max_pasid_log < 0) + return -ENOSPC; + max_pasid = 1 << fn->config.max_pasid_log; + return range_alloc(&fn->pasid_list, size, max_pasid, "afu pasid"); +} + +void ocxl_pasid_afu_free(struct ocxl_fn *fn, u32 start, u32 size) +{ + return range_free(&fn->pasid_list, start, size, "afu pasid"); +} + +int ocxl_actag_afu_alloc(struct ocxl_fn *fn, u32 size) +{ + int max_actag; + + max_actag = fn->actag_enabled; + return range_alloc(&fn->actag_list, size, max_actag, "afu actag"); +} + +void ocxl_actag_afu_free(struct ocxl_fn *fn, u32 start, u32 size) +{ + return range_free(&fn->actag_list, start, size, "afu actag"); +} diff --git a/drivers/misc/ocxl/pci.c b/drivers/misc/ocxl/pci.c new file mode 100644 index 000000000000..0051d9ec76cc --- /dev/null +++ b/drivers/misc/ocxl/pci.c @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include +#include +#include +#include "ocxl_internal.h" + +/* + * Any opencapi device which wants to use this 'generic' driver should + * use the 0x062B device ID. Vendors should define the subsystem + * vendor/device ID to help differentiate devices. + */ +static const struct pci_device_id ocxl_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x062B), }, + { } +}; +MODULE_DEVICE_TABLE(pci, ocxl_pci_tbl); + + +static struct ocxl_fn *ocxl_fn_get(struct ocxl_fn *fn) +{ + return (get_device(&fn->dev) == NULL) ? NULL : fn; +} + +static void ocxl_fn_put(struct ocxl_fn *fn) +{ + put_device(&fn->dev); +} + +struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu) +{ + return (get_device(&afu->dev) == NULL) ? NULL : afu; +} + +void ocxl_afu_put(struct ocxl_afu *afu) +{ + put_device(&afu->dev); +} + +static struct ocxl_afu *alloc_afu(struct ocxl_fn *fn) +{ + struct ocxl_afu *afu; + + afu = kzalloc(sizeof(struct ocxl_afu), GFP_KERNEL); + if (!afu) + return NULL; + + mutex_init(&afu->contexts_lock); + mutex_init(&afu->afu_control_lock); + idr_init(&afu->contexts_idr); + afu->fn = fn; + ocxl_fn_get(fn); + return afu; +} + +static void free_afu(struct ocxl_afu *afu) +{ + idr_destroy(&afu->contexts_idr); + ocxl_fn_put(afu->fn); + kfree(afu); +} + +static void free_afu_dev(struct device *dev) +{ + struct ocxl_afu *afu = to_ocxl_afu(dev); + + ocxl_unregister_afu(afu); + free_afu(afu); +} + +static int set_afu_device(struct ocxl_afu *afu, const char *location) +{ + struct ocxl_fn *fn = afu->fn; + int rc; + + afu->dev.parent = &fn->dev; + afu->dev.release = free_afu_dev; + rc = dev_set_name(&afu->dev, "%s.%s.%hhu", afu->config.name, location, + afu->config.idx); + return rc; +} + +static int assign_afu_actag(struct ocxl_afu *afu, struct pci_dev *dev) +{ + struct ocxl_fn *fn = afu->fn; + int actag_count, actag_offset; + + /* + * if there were not enough actags for the function, each afu + * reduces its count as well + */ + actag_count = afu->config.actag_supported * + fn->actag_enabled / fn->actag_supported; + actag_offset = ocxl_actag_afu_alloc(fn, actag_count); + if (actag_offset < 0) { + dev_err(&afu->dev, "Can't allocate %d actags for AFU: %d\n", + actag_count, actag_offset); + return actag_offset; + } + afu->actag_base = fn->actag_base + actag_offset; + afu->actag_enabled = actag_count; + + ocxl_config_set_afu_actag(dev, afu->config.dvsec_afu_control_pos, + afu->actag_base, afu->actag_enabled); + dev_dbg(&afu->dev, "actag base=%d enabled=%d\n", + afu->actag_base, afu->actag_enabled); + return 0; +} + +static void reclaim_afu_actag(struct ocxl_afu *afu) +{ + struct ocxl_fn *fn = afu->fn; + int start_offset, size; + + start_offset = afu->actag_base - fn->actag_base; + size = afu->actag_enabled; + ocxl_actag_afu_free(afu->fn, start_offset, size); +} + +static int assign_afu_pasid(struct ocxl_afu *afu, struct pci_dev *dev) +{ + struct ocxl_fn *fn = afu->fn; + int pasid_count, pasid_offset; + + /* + * We only support the case where the function configuration + * requested enough PASIDs to cover all AFUs. + */ + pasid_count = 1 << afu->config.pasid_supported_log; + pasid_offset = ocxl_pasid_afu_alloc(fn, pasid_count); + if (pasid_offset < 0) { + dev_err(&afu->dev, "Can't allocate %d PASIDs for AFU: %d\n", + pasid_count, pasid_offset); + return pasid_offset; + } + afu->pasid_base = fn->pasid_base + pasid_offset; + afu->pasid_count = 0; + afu->pasid_max = pasid_count; + + ocxl_config_set_afu_pasid(dev, afu->config.dvsec_afu_control_pos, + afu->pasid_base, + afu->config.pasid_supported_log); + dev_dbg(&afu->dev, "PASID base=%d, enabled=%d\n", + afu->pasid_base, pasid_count); + return 0; +} + +static void reclaim_afu_pasid(struct ocxl_afu *afu) +{ + struct ocxl_fn *fn = afu->fn; + int start_offset, size; + + start_offset = afu->pasid_base - fn->pasid_base; + size = 1 << afu->config.pasid_supported_log; + ocxl_pasid_afu_free(afu->fn, start_offset, size); +} + +static int reserve_fn_bar(struct ocxl_fn *fn, int bar) +{ + struct pci_dev *dev = to_pci_dev(fn->dev.parent); + int rc, idx; + + if (bar != 0 && bar != 2 && bar != 4) + return -EINVAL; + + idx = bar >> 1; + if (fn->bar_used[idx]++ == 0) { + rc = pci_request_region(dev, bar, "ocxl"); + if (rc) + return rc; + } + return 0; +} + +static void release_fn_bar(struct ocxl_fn *fn, int bar) +{ + struct pci_dev *dev = to_pci_dev(fn->dev.parent); + int idx; + + if (bar != 0 && bar != 2 && bar != 4) + return; + + idx = bar >> 1; + if (--fn->bar_used[idx] == 0) + pci_release_region(dev, bar); + WARN_ON(fn->bar_used[idx] < 0); +} + +static int map_mmio_areas(struct ocxl_afu *afu, struct pci_dev *dev) +{ + int rc; + + rc = reserve_fn_bar(afu->fn, afu->config.global_mmio_bar); + if (rc) + return rc; + + rc = reserve_fn_bar(afu->fn, afu->config.pp_mmio_bar); + if (rc) { + release_fn_bar(afu->fn, afu->config.global_mmio_bar); + return rc; + } + + afu->global_mmio_start = + pci_resource_start(dev, afu->config.global_mmio_bar) + + afu->config.global_mmio_offset; + afu->pp_mmio_start = + pci_resource_start(dev, afu->config.pp_mmio_bar) + + afu->config.pp_mmio_offset; + + afu->global_mmio_ptr = ioremap(afu->global_mmio_start, + afu->config.global_mmio_size); + if (!afu->global_mmio_ptr) { + release_fn_bar(afu->fn, afu->config.pp_mmio_bar); + release_fn_bar(afu->fn, afu->config.global_mmio_bar); + dev_err(&dev->dev, "Error mapping global mmio area\n"); + return -ENOMEM; + } + + /* + * Leave an empty page between the per-process mmio area and + * the AFU interrupt mappings + */ + afu->irq_base_offset = afu->config.pp_mmio_stride + PAGE_SIZE; + return 0; +} + +static void unmap_mmio_areas(struct ocxl_afu *afu) +{ + if (afu->global_mmio_ptr) { + iounmap(afu->global_mmio_ptr); + afu->global_mmio_ptr = NULL; + } + afu->global_mmio_start = 0; + afu->pp_mmio_start = 0; + release_fn_bar(afu->fn, afu->config.pp_mmio_bar); + release_fn_bar(afu->fn, afu->config.global_mmio_bar); +} + +static int configure_afu(struct ocxl_afu *afu, u8 afu_idx, struct pci_dev *dev) +{ + int rc; + + rc = ocxl_config_read_afu(dev, &afu->fn->config, &afu->config, afu_idx); + if (rc) + return rc; + + rc = set_afu_device(afu, dev_name(&dev->dev)); + if (rc) + return rc; + + rc = assign_afu_actag(afu, dev); + if (rc) + return rc; + + rc = assign_afu_pasid(afu, dev); + if (rc) { + reclaim_afu_actag(afu); + return rc; + } + + rc = map_mmio_areas(afu, dev); + if (rc) { + reclaim_afu_pasid(afu); + reclaim_afu_actag(afu); + return rc; + } + return 0; +} + +static void deconfigure_afu(struct ocxl_afu *afu) +{ + unmap_mmio_areas(afu); + reclaim_afu_pasid(afu); + reclaim_afu_actag(afu); +} + +static int activate_afu(struct pci_dev *dev, struct ocxl_afu *afu) +{ + int rc; + + ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1); + /* + * Char device creation is the last step, as processes can + * call our driver immediately, so all our inits must be finished. + */ + rc = ocxl_create_cdev(afu); + if (rc) + return rc; + return 0; +} + +static void deactivate_afu(struct ocxl_afu *afu) +{ + struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent); + + ocxl_destroy_cdev(afu); + ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 0); +} + +static int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx) +{ + int rc; + struct ocxl_afu *afu; + + afu = alloc_afu(fn); + if (!afu) + return -ENOMEM; + + rc = configure_afu(afu, afu_idx, dev); + if (rc) { + free_afu(afu); + return rc; + } + + rc = ocxl_register_afu(afu); + if (rc) + goto err; + + rc = ocxl_sysfs_add_afu(afu); + if (rc) + goto err; + + rc = activate_afu(dev, afu); + if (rc) + goto err_sys; + + list_add_tail(&afu->list, &fn->afu_list); + return 0; + +err_sys: + ocxl_sysfs_remove_afu(afu); +err: + deconfigure_afu(afu); + device_unregister(&afu->dev); + return rc; +} + +static void remove_afu(struct ocxl_afu *afu) +{ + list_del(&afu->list); + ocxl_context_detach_all(afu); + deactivate_afu(afu); + ocxl_sysfs_remove_afu(afu); + deconfigure_afu(afu); + device_unregister(&afu->dev); +} + +static struct ocxl_fn *alloc_function(struct pci_dev *dev) +{ + struct ocxl_fn *fn; + + fn = kzalloc(sizeof(struct ocxl_fn), GFP_KERNEL); + if (!fn) + return NULL; + + INIT_LIST_HEAD(&fn->afu_list); + INIT_LIST_HEAD(&fn->pasid_list); + INIT_LIST_HEAD(&fn->actag_list); + return fn; +} + +static void free_function(struct ocxl_fn *fn) +{ + WARN_ON(!list_empty(&fn->afu_list)); + WARN_ON(!list_empty(&fn->pasid_list)); + kfree(fn); +} + +static void free_function_dev(struct device *dev) +{ + struct ocxl_fn *fn = to_ocxl_function(dev); + + free_function(fn); +} + +static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev) +{ + int rc; + + fn->dev.parent = &dev->dev; + fn->dev.release = free_function_dev; + rc = dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev)); + if (rc) + return rc; + pci_set_drvdata(dev, fn); + return 0; +} + +static int assign_function_actag(struct ocxl_fn *fn) +{ + struct pci_dev *dev = to_pci_dev(fn->dev.parent); + u16 base, enabled, supported; + int rc; + + rc = ocxl_config_get_actag_info(dev, &base, &enabled, &supported); + if (rc) + return rc; + + fn->actag_base = base; + fn->actag_enabled = enabled; + fn->actag_supported = supported; + + ocxl_config_set_actag(dev, fn->config.dvsec_function_pos, + fn->actag_base, fn->actag_enabled); + dev_dbg(&fn->dev, "actag range starting at %d, enabled %d\n", + fn->actag_base, fn->actag_enabled); + return 0; +} + +static int set_function_pasid(struct ocxl_fn *fn) +{ + struct pci_dev *dev = to_pci_dev(fn->dev.parent); + int rc, desired_count, max_count; + + /* A function may not require any PASID */ + if (fn->config.max_pasid_log < 0) + return 0; + + rc = ocxl_config_get_pasid_info(dev, &max_count); + if (rc) + return rc; + + desired_count = 1 << fn->config.max_pasid_log; + + if (desired_count > max_count) { + dev_err(&fn->dev, + "Function requires more PASIDs than is available (%d vs. %d)\n", + desired_count, max_count); + return -ENOSPC; + } + + fn->pasid_base = 0; + return 0; +} + +static int configure_function(struct ocxl_fn *fn, struct pci_dev *dev) +{ + int rc; + + rc = pci_enable_device(dev); + if (rc) { + dev_err(&dev->dev, "pci_enable_device failed: %d\n", rc); + return rc; + } + + /* + * Once it has been confirmed to work on our hardware, we + * should reset the function, to force the adapter to restart + * from scratch. + * A function reset would also reset all its AFUs. + * + * Some hints for implementation: + * + * - there's not status bit to know when the reset is done. We + * should try reading the config space to know when it's + * done. + * - probably something like: + * Reset + * wait 100ms + * issue config read + * allow device up to 1 sec to return success on config + * read before declaring it broken + * + * Some shared logic on the card (CFG, TLX) won't be reset, so + * there's no guarantee that it will be enough. + */ + rc = ocxl_config_read_function(dev, &fn->config); + if (rc) + return rc; + + rc = set_function_device(fn, dev); + if (rc) + return rc; + + rc = assign_function_actag(fn); + if (rc) + return rc; + + rc = set_function_pasid(fn); + if (rc) + return rc; + + rc = ocxl_link_setup(dev, 0, &fn->link); + if (rc) + return rc; + + rc = ocxl_config_set_TL(dev, fn->config.dvsec_tl_pos); + if (rc) { + ocxl_link_release(dev, fn->link); + return rc; + } + return 0; +} + +static void deconfigure_function(struct ocxl_fn *fn) +{ + struct pci_dev *dev = to_pci_dev(fn->dev.parent); + + ocxl_link_release(dev, fn->link); + pci_disable_device(dev); +} + +static struct ocxl_fn *init_function(struct pci_dev *dev) +{ + struct ocxl_fn *fn; + int rc; + + fn = alloc_function(dev); + if (!fn) + return ERR_PTR(-ENOMEM); + + rc = configure_function(fn, dev); + if (rc) { + free_function(fn); + return ERR_PTR(rc); + } + + rc = device_register(&fn->dev); + if (rc) { + deconfigure_function(fn); + device_unregister(&fn->dev); + return ERR_PTR(rc); + } + return fn; +} + +static void remove_function(struct ocxl_fn *fn) +{ + deconfigure_function(fn); + device_unregister(&fn->dev); +} + +static int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int rc, afu_count = 0; + u8 afu; + struct ocxl_fn *fn; + + if (!radix_enabled()) { + dev_err(&dev->dev, "Unsupported memory model (hash)\n"); + return -ENODEV; + } + + fn = init_function(dev); + if (IS_ERR(fn)) { + dev_err(&dev->dev, "function init failed: %li\n", + PTR_ERR(fn)); + return PTR_ERR(fn); + } + + for (afu = 0; afu <= fn->config.max_afu_index; afu++) { + rc = ocxl_config_check_afu_index(dev, &fn->config, afu); + if (rc > 0) { + rc = init_afu(dev, fn, afu); + if (rc) { + dev_err(&dev->dev, + "Can't initialize AFU index %d\n", afu); + continue; + } + afu_count++; + } + } + dev_info(&dev->dev, "%d AFU(s) configured\n", afu_count); + return 0; +} + +static void ocxl_remove(struct pci_dev *dev) +{ + struct ocxl_afu *afu, *tmp; + struct ocxl_fn *fn = pci_get_drvdata(dev); + + list_for_each_entry_safe(afu, tmp, &fn->afu_list, list) { + remove_afu(afu); + } + remove_function(fn); +} + +struct pci_driver ocxl_pci_driver = { + .name = "ocxl", + .id_table = ocxl_pci_tbl, + .probe = ocxl_probe, + .remove = ocxl_remove, + .shutdown = ocxl_remove, +}; diff --git a/drivers/misc/ocxl/sysfs.c b/drivers/misc/ocxl/sysfs.c new file mode 100644 index 000000000000..d9753a1db14b --- /dev/null +++ b/drivers/misc/ocxl/sysfs.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include "ocxl_internal.h" + +static ssize_t global_mmio_size_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct ocxl_afu *afu = to_ocxl_afu(device); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + afu->config.global_mmio_size); +} + +static ssize_t pp_mmio_size_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct ocxl_afu *afu = to_ocxl_afu(device); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + afu->config.pp_mmio_stride); +} + +static ssize_t afu_version_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct ocxl_afu *afu = to_ocxl_afu(device); + + return scnprintf(buf, PAGE_SIZE, "%hhu:%hhu\n", + afu->config.version_major, + afu->config.version_minor); +} + +static ssize_t contexts_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct ocxl_afu *afu = to_ocxl_afu(device); + + return scnprintf(buf, PAGE_SIZE, "%d/%d\n", + afu->pasid_count, afu->pasid_max); +} + +static struct device_attribute afu_attrs[] = { + __ATTR_RO(global_mmio_size), + __ATTR_RO(pp_mmio_size), + __ATTR_RO(afu_version), + __ATTR_RO(contexts), +}; + +static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct ocxl_afu *afu = to_ocxl_afu(kobj_to_dev(kobj)); + + if (count == 0 || off < 0 || + off >= afu->config.global_mmio_size) + return 0; + memcpy_fromio(buf, afu->global_mmio_ptr + off, count); + return count; +} + +static int global_mmio_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct ocxl_afu *afu = vma->vm_private_data; + unsigned long offset; + + if (vmf->pgoff >= (afu->config.global_mmio_size >> PAGE_SHIFT)) + return VM_FAULT_SIGBUS; + + offset = vmf->pgoff; + offset += (afu->global_mmio_start >> PAGE_SHIFT); + vm_insert_pfn(vma, vmf->address, offset); + return VM_FAULT_NOPAGE; +} + +static const struct vm_operations_struct global_mmio_vmops = { + .fault = global_mmio_fault, +}; + +static int global_mmio_mmap(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + struct vm_area_struct *vma) +{ + struct ocxl_afu *afu = to_ocxl_afu(kobj_to_dev(kobj)); + + if ((vma_pages(vma) + vma->vm_pgoff) > + (afu->config.global_mmio_size >> PAGE_SHIFT)) + return -EINVAL; + + vma->vm_flags |= VM_IO | VM_PFNMAP; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_ops = &global_mmio_vmops; + vma->vm_private_data = afu; + return 0; +} + +int ocxl_sysfs_add_afu(struct ocxl_afu *afu) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { + rc = device_create_file(&afu->dev, &afu_attrs[i]); + if (rc) + goto err; + } + + sysfs_attr_init(&afu->attr_global_mmio.attr); + afu->attr_global_mmio.attr.name = "global_mmio_area"; + afu->attr_global_mmio.attr.mode = 0600; + afu->attr_global_mmio.size = afu->config.global_mmio_size; + afu->attr_global_mmio.read = global_mmio_read; + afu->attr_global_mmio.mmap = global_mmio_mmap; + rc = device_create_bin_file(&afu->dev, &afu->attr_global_mmio); + if (rc) { + dev_err(&afu->dev, + "Unable to create global mmio attr for afu: %d\n", + rc); + goto err; + } + + return 0; + +err: + for (i--; i >= 0; i--) + device_remove_file(&afu->dev, &afu_attrs[i]); + return rc; +} + +void ocxl_sysfs_remove_afu(struct ocxl_afu *afu) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) + device_remove_file(&afu->dev, &afu_attrs[i]); + device_remove_bin_file(&afu->dev, &afu->attr_global_mmio); +} -- cgit From aeddad1760aeb206d912b27b230269407efd5b06 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 23 Jan 2018 12:31:42 +0100 Subject: ocxl: Add AFU interrupt support Add user APIs through ioctl to allocate, free, and be notified of an AFU interrupt. For opencapi, an AFU can trigger an interrupt on the host by sending a specific command targeting a 64-bit object handle. On POWER9, this is implemented by mapping a special page in the address space of a process and a write to that page will trigger an interrupt. Signed-off-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/afu_irq.c | 197 ++++++++++++++++++++++++++++++++++++++ drivers/misc/ocxl/context.c | 51 +++++++++- drivers/misc/ocxl/file.c | 34 +++++++ drivers/misc/ocxl/link.c | 28 ++++++ drivers/misc/ocxl/ocxl_internal.h | 7 ++ 5 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 drivers/misc/ocxl/afu_irq.c (limited to 'drivers') diff --git a/drivers/misc/ocxl/afu_irq.c b/drivers/misc/ocxl/afu_irq.c new file mode 100644 index 000000000000..f40d853de401 --- /dev/null +++ b/drivers/misc/ocxl/afu_irq.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#include +#include +#include +#include "ocxl_internal.h" + +struct afu_irq { + int id; + int hw_irq; + unsigned int virq; + char *name; + u64 trigger_page; + struct eventfd_ctx *ev_ctx; +}; + +static int irq_offset_to_id(struct ocxl_context *ctx, u64 offset) +{ + return (offset - ctx->afu->irq_base_offset) >> PAGE_SHIFT; +} + +static u64 irq_id_to_offset(struct ocxl_context *ctx, int id) +{ + return ctx->afu->irq_base_offset + (id << PAGE_SHIFT); +} + +static irqreturn_t afu_irq_handler(int virq, void *data) +{ + struct afu_irq *irq = (struct afu_irq *) data; + + if (irq->ev_ctx) + eventfd_signal(irq->ev_ctx, 1); + return IRQ_HANDLED; +} + +static int setup_afu_irq(struct ocxl_context *ctx, struct afu_irq *irq) +{ + int rc; + + irq->virq = irq_create_mapping(NULL, irq->hw_irq); + if (!irq->virq) { + pr_err("irq_create_mapping failed\n"); + return -ENOMEM; + } + pr_debug("hw_irq %d mapped to virq %u\n", irq->hw_irq, irq->virq); + + irq->name = kasprintf(GFP_KERNEL, "ocxl-afu-%u", irq->virq); + if (!irq->name) { + irq_dispose_mapping(irq->virq); + return -ENOMEM; + } + + rc = request_irq(irq->virq, afu_irq_handler, 0, irq->name, irq); + if (rc) { + kfree(irq->name); + irq->name = NULL; + irq_dispose_mapping(irq->virq); + pr_err("request_irq failed: %d\n", rc); + return rc; + } + return 0; +} + +static void release_afu_irq(struct afu_irq *irq) +{ + free_irq(irq->virq, irq); + irq_dispose_mapping(irq->virq); + kfree(irq->name); +} + +int ocxl_afu_irq_alloc(struct ocxl_context *ctx, u64 *irq_offset) +{ + struct afu_irq *irq; + int rc; + + irq = kzalloc(sizeof(struct afu_irq), GFP_KERNEL); + if (!irq) + return -ENOMEM; + + /* + * We limit the number of afu irqs per context and per link to + * avoid a single process or user depleting the pool of IPIs + */ + + mutex_lock(&ctx->irq_lock); + + irq->id = idr_alloc(&ctx->irq_idr, irq, 0, MAX_IRQ_PER_CONTEXT, + GFP_KERNEL); + if (irq->id < 0) { + rc = -ENOSPC; + goto err_unlock; + } + + rc = ocxl_link_irq_alloc(ctx->afu->fn->link, &irq->hw_irq, + &irq->trigger_page); + if (rc) + goto err_idr; + + rc = setup_afu_irq(ctx, irq); + if (rc) + goto err_alloc; + + *irq_offset = irq_id_to_offset(ctx, irq->id); + + mutex_unlock(&ctx->irq_lock); + return 0; + +err_alloc: + ocxl_link_free_irq(ctx->afu->fn->link, irq->hw_irq); +err_idr: + idr_remove(&ctx->irq_idr, irq->id); +err_unlock: + mutex_unlock(&ctx->irq_lock); + kfree(irq); + return rc; +} + +static void afu_irq_free(struct afu_irq *irq, struct ocxl_context *ctx) +{ + if (ctx->mapping) + unmap_mapping_range(ctx->mapping, + irq_id_to_offset(ctx, irq->id), + 1 << PAGE_SHIFT, 1); + release_afu_irq(irq); + if (irq->ev_ctx) + eventfd_ctx_put(irq->ev_ctx); + ocxl_link_free_irq(ctx->afu->fn->link, irq->hw_irq); + kfree(irq); +} + +int ocxl_afu_irq_free(struct ocxl_context *ctx, u64 irq_offset) +{ + struct afu_irq *irq; + int id = irq_offset_to_id(ctx, irq_offset); + + mutex_lock(&ctx->irq_lock); + + irq = idr_find(&ctx->irq_idr, id); + if (!irq) { + mutex_unlock(&ctx->irq_lock); + return -EINVAL; + } + idr_remove(&ctx->irq_idr, irq->id); + afu_irq_free(irq, ctx); + mutex_unlock(&ctx->irq_lock); + return 0; +} + +void ocxl_afu_irq_free_all(struct ocxl_context *ctx) +{ + struct afu_irq *irq; + int id; + + mutex_lock(&ctx->irq_lock); + idr_for_each_entry(&ctx->irq_idr, irq, id) + afu_irq_free(irq, ctx); + mutex_unlock(&ctx->irq_lock); +} + +int ocxl_afu_irq_set_fd(struct ocxl_context *ctx, u64 irq_offset, int eventfd) +{ + struct afu_irq *irq; + struct eventfd_ctx *ev_ctx; + int rc = 0, id = irq_offset_to_id(ctx, irq_offset); + + mutex_lock(&ctx->irq_lock); + irq = idr_find(&ctx->irq_idr, id); + if (!irq) { + rc = -EINVAL; + goto unlock; + } + + ev_ctx = eventfd_ctx_fdget(eventfd); + if (IS_ERR(ev_ctx)) { + rc = -EINVAL; + goto unlock; + } + + irq->ev_ctx = ev_ctx; +unlock: + mutex_unlock(&ctx->irq_lock); + return rc; +} + +u64 ocxl_afu_irq_get_addr(struct ocxl_context *ctx, u64 irq_offset) +{ + struct afu_irq *irq; + int id = irq_offset_to_id(ctx, irq_offset); + u64 addr = 0; + + mutex_lock(&ctx->irq_lock); + irq = idr_find(&ctx->irq_idr, id); + if (irq) + addr = irq->trigger_page; + mutex_unlock(&ctx->irq_lock); + return addr; +} diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c index b34b836f924c..269149490063 100644 --- a/drivers/misc/ocxl/context.c +++ b/drivers/misc/ocxl/context.c @@ -31,6 +31,8 @@ int ocxl_context_init(struct ocxl_context *ctx, struct ocxl_afu *afu, mutex_init(&ctx->mapping_lock); init_waitqueue_head(&ctx->events_wq); mutex_init(&ctx->xsl_error_lock); + mutex_init(&ctx->irq_lock); + idr_init(&ctx->irq_idr); /* * Keep a reference on the AFU to make sure it's valid for the * duration of the life of the context @@ -80,6 +82,19 @@ out: return rc; } +static int map_afu_irq(struct vm_area_struct *vma, unsigned long address, + u64 offset, struct ocxl_context *ctx) +{ + u64 trigger_addr; + + trigger_addr = ocxl_afu_irq_get_addr(ctx, offset); + if (!trigger_addr) + return VM_FAULT_SIGBUS; + + vm_insert_pfn(vma, address, trigger_addr >> PAGE_SHIFT); + return VM_FAULT_NOPAGE; +} + static int map_pp_mmio(struct vm_area_struct *vma, unsigned long address, u64 offset, struct ocxl_context *ctx) { @@ -118,7 +133,10 @@ static int ocxl_mmap_fault(struct vm_fault *vmf) pr_debug("%s: pasid %d address 0x%lx offset 0x%llx\n", __func__, ctx->pasid, vmf->address, offset); - rc = map_pp_mmio(vma, vmf->address, offset, ctx); + if (offset < ctx->afu->irq_base_offset) + rc = map_pp_mmio(vma, vmf->address, offset, ctx); + else + rc = map_afu_irq(vma, vmf->address, offset, ctx); return rc; } @@ -126,6 +144,30 @@ static const struct vm_operations_struct ocxl_vmops = { .fault = ocxl_mmap_fault, }; +static int check_mmap_afu_irq(struct ocxl_context *ctx, + struct vm_area_struct *vma) +{ + /* only one page */ + if (vma_pages(vma) != 1) + return -EINVAL; + + /* check offset validty */ + if (!ocxl_afu_irq_get_addr(ctx, vma->vm_pgoff << PAGE_SHIFT)) + return -EINVAL; + + /* + * trigger page should only be accessible in write mode. + * + * It's a bit theoretical, as a page mmaped with only + * PROT_WRITE is currently readable, but it doesn't hurt. + */ + if ((vma->vm_flags & VM_READ) || (vma->vm_flags & VM_EXEC) || + !(vma->vm_flags & VM_WRITE)) + return -EINVAL; + vma->vm_flags &= ~(VM_MAYREAD | VM_MAYEXEC); + return 0; +} + static int check_mmap_mmio(struct ocxl_context *ctx, struct vm_area_struct *vma) { @@ -139,7 +181,10 @@ int ocxl_context_mmap(struct ocxl_context *ctx, struct vm_area_struct *vma) { int rc; - rc = check_mmap_mmio(ctx, vma); + if ((vma->vm_pgoff << PAGE_SHIFT) < ctx->afu->irq_base_offset) + rc = check_mmap_mmio(ctx, vma); + else + rc = check_mmap_afu_irq(ctx, vma); if (rc) return rc; @@ -224,6 +269,8 @@ void ocxl_context_free(struct ocxl_context *ctx) idr_remove(&ctx->afu->contexts_idr, ctx->pasid); mutex_unlock(&ctx->afu->contexts_lock); + ocxl_afu_irq_free_all(ctx); + idr_destroy(&ctx->irq_idr); /* reference to the AFU taken in ocxl_context_init */ ocxl_afu_put(ctx->afu); kfree(ctx); diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index 6f0befda6a8a..c90c1a578d2f 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -103,12 +103,17 @@ static long afu_ioctl_attach(struct ocxl_context *ctx, } #define CMD_STR(x) (x == OCXL_IOCTL_ATTACH ? "ATTACH" : \ + x == OCXL_IOCTL_IRQ_ALLOC ? "IRQ_ALLOC" : \ + x == OCXL_IOCTL_IRQ_FREE ? "IRQ_FREE" : \ + x == OCXL_IOCTL_IRQ_SET_FD ? "IRQ_SET_FD" : \ "UNKNOWN") static long afu_ioctl(struct file *file, unsigned int cmd, unsigned long args) { struct ocxl_context *ctx = file->private_data; + struct ocxl_ioctl_irq_fd irq_fd; + u64 irq_offset; long rc; pr_debug("%s for context %d, command %s\n", __func__, ctx->pasid, @@ -123,6 +128,35 @@ static long afu_ioctl(struct file *file, unsigned int cmd, (struct ocxl_ioctl_attach __user *) args); break; + case OCXL_IOCTL_IRQ_ALLOC: + rc = ocxl_afu_irq_alloc(ctx, &irq_offset); + if (!rc) { + rc = copy_to_user((u64 __user *) args, &irq_offset, + sizeof(irq_offset)); + if (rc) + ocxl_afu_irq_free(ctx, irq_offset); + } + break; + + case OCXL_IOCTL_IRQ_FREE: + rc = copy_from_user(&irq_offset, (u64 __user *) args, + sizeof(irq_offset)); + if (rc) + return -EFAULT; + rc = ocxl_afu_irq_free(ctx, irq_offset); + break; + + case OCXL_IOCTL_IRQ_SET_FD: + rc = copy_from_user(&irq_fd, (u64 __user *) args, + sizeof(irq_fd)); + if (rc) + return -EFAULT; + if (irq_fd.reserved) + return -EINVAL; + rc = ocxl_afu_irq_set_fd(ctx, irq_fd.irq_offset, + irq_fd.eventfd); + break; + default: rc = -EINVAL; } diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c index 64d7a98c904a..8bdcef9c3cba 100644 --- a/drivers/misc/ocxl/link.c +++ b/drivers/misc/ocxl/link.c @@ -601,3 +601,31 @@ unlock: mutex_unlock(&spa->spa_lock); return rc; } + +int ocxl_link_irq_alloc(void *link_handle, int *hw_irq, u64 *trigger_addr) +{ + struct link *link = (struct link *) link_handle; + int rc, irq; + u64 addr; + + if (atomic_dec_if_positive(&link->irq_available) < 0) + return -ENOSPC; + + rc = pnv_ocxl_alloc_xive_irq(&irq, &addr); + if (rc) { + atomic_inc(&link->irq_available); + return rc; + } + + *hw_irq = irq; + *trigger_addr = addr; + return 0; +} + +void ocxl_link_free_irq(void *link_handle, int hw_irq) +{ + struct link *link = (struct link *) link_handle; + + pnv_ocxl_free_xive_irq(hw_irq); + atomic_inc(&link->irq_available); +} diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h index 04fc160c7bd5..a89b88ac67eb 100644 --- a/drivers/misc/ocxl/ocxl_internal.h +++ b/drivers/misc/ocxl/ocxl_internal.h @@ -190,4 +190,11 @@ extern void ocxl_context_free(struct ocxl_context *ctx); extern int ocxl_sysfs_add_afu(struct ocxl_afu *afu); extern void ocxl_sysfs_remove_afu(struct ocxl_afu *afu); +extern int ocxl_afu_irq_alloc(struct ocxl_context *ctx, u64 *irq_offset); +extern int ocxl_afu_irq_free(struct ocxl_context *ctx, u64 irq_offset); +extern void ocxl_afu_irq_free_all(struct ocxl_context *ctx); +extern int ocxl_afu_irq_set_fd(struct ocxl_context *ctx, u64 irq_offset, + int eventfd); +extern u64 ocxl_afu_irq_get_addr(struct ocxl_context *ctx, u64 irq_offset); + #endif /* _OCXL_INTERNAL_H_ */ -- cgit From 280b983ce2b8759722d911ea4b5af66e95d84e09 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 23 Jan 2018 12:31:43 +0100 Subject: ocxl: Add a kernel API for other opencapi drivers Some of the functions done by the generic driver should also be needed by other opencapi drivers: attaching a context to an adapter, translation fault handling, AFU interrupt allocation... So to avoid code duplication, the driver provides a kernel API that other drivers can use, similar to calling a in-kernel library. It is still a bit theoretical, for lack of real hardware, and will likely need adjustements down the road. But we used the cxlflash driver as a guinea pig. Signed-off-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/config.c | 13 ++++++- drivers/misc/ocxl/link.c | 7 ++++ drivers/misc/ocxl/ocxl_internal.h | 71 +-------------------------------------- 3 files changed, 20 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ocxl/config.c b/drivers/misc/ocxl/config.c index ea8cca50ea06..2e30de9c694a 100644 --- a/drivers/misc/ocxl/config.c +++ b/drivers/misc/ocxl/config.c @@ -2,8 +2,8 @@ // Copyright 2017 IBM Corp. #include #include +#include #include -#include "ocxl_internal.h" #define EXTRACT_BIT(val, bit) (!!(val & BIT(bit))) #define EXTRACT_BITS(val, s, e) ((val & GENMASK(e, s)) >> s) @@ -243,6 +243,7 @@ int ocxl_config_read_function(struct pci_dev *dev, struct ocxl_fn_config *fn) rc = validate_function(dev, fn); return rc; } +EXPORT_SYMBOL_GPL(ocxl_config_read_function); static int read_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn, int offset, u32 *data) @@ -301,6 +302,7 @@ int ocxl_config_check_afu_index(struct pci_dev *dev, } return 1; } +EXPORT_SYMBOL_GPL(ocxl_config_check_afu_index); static int read_afu_name(struct pci_dev *dev, struct ocxl_fn_config *fn, struct ocxl_afu_config *afu) @@ -498,6 +500,7 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn, rc = validate_afu(dev, afu); return rc; } +EXPORT_SYMBOL_GPL(ocxl_config_read_afu); int ocxl_config_get_actag_info(struct pci_dev *dev, u16 *base, u16 *enabled, u16 *supported) @@ -516,6 +519,7 @@ int ocxl_config_get_actag_info(struct pci_dev *dev, u16 *base, u16 *enabled, } return 0; } +EXPORT_SYMBOL_GPL(ocxl_config_get_actag_info); void ocxl_config_set_afu_actag(struct pci_dev *dev, int pos, int actag_base, int actag_count) @@ -528,11 +532,13 @@ void ocxl_config_set_afu_actag(struct pci_dev *dev, int pos, int actag_base, val = actag_base & OCXL_DVSEC_ACTAG_MASK; pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_BASE, val); } +EXPORT_SYMBOL_GPL(ocxl_config_set_afu_actag); int ocxl_config_get_pasid_info(struct pci_dev *dev, int *count) { return pnv_ocxl_get_pasid_count(dev, count); } +EXPORT_SYMBOL_GPL(ocxl_config_get_pasid_info); void ocxl_config_set_afu_pasid(struct pci_dev *dev, int pos, int pasid_base, u32 pasid_count_log) @@ -550,6 +556,7 @@ void ocxl_config_set_afu_pasid(struct pci_dev *dev, int pos, int pasid_base, pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_BASE, val32); } +EXPORT_SYMBOL_GPL(ocxl_config_set_afu_pasid); void ocxl_config_set_afu_state(struct pci_dev *dev, int pos, int enable) { @@ -562,6 +569,7 @@ void ocxl_config_set_afu_state(struct pci_dev *dev, int pos, int enable) val &= 0xFE; pci_write_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_ENABLE, val); } +EXPORT_SYMBOL_GPL(ocxl_config_set_afu_state); int ocxl_config_set_TL(struct pci_dev *dev, int tl_dvsec) { @@ -660,6 +668,7 @@ out: kfree(recv_rate); return rc; } +EXPORT_SYMBOL_GPL(ocxl_config_set_TL); int ocxl_config_terminate_pasid(struct pci_dev *dev, int afu_control, int pasid) { @@ -699,6 +708,7 @@ int ocxl_config_terminate_pasid(struct pci_dev *dev, int afu_control, int pasid) } return 0; } +EXPORT_SYMBOL_GPL(ocxl_config_terminate_pasid); void ocxl_config_set_actag(struct pci_dev *dev, int func_dvsec, u32 tag_first, u32 tag_count) @@ -710,3 +720,4 @@ void ocxl_config_set_actag(struct pci_dev *dev, int func_dvsec, u32 tag_first, pci_write_config_dword(dev, func_dvsec + OCXL_DVSEC_FUNC_OFF_ACTAG, val); } +EXPORT_SYMBOL_GPL(ocxl_config_set_actag); diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c index 8bdcef9c3cba..fbca3feec592 100644 --- a/drivers/misc/ocxl/link.c +++ b/drivers/misc/ocxl/link.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "ocxl_internal.h" @@ -420,6 +421,7 @@ unlock: mutex_unlock(&links_list_lock); return rc; } +EXPORT_SYMBOL_GPL(ocxl_link_setup); static void release_xsl(struct kref *ref) { @@ -439,6 +441,7 @@ void ocxl_link_release(struct pci_dev *dev, void *link_handle) kref_put(&link->ref, release_xsl); mutex_unlock(&links_list_lock); } +EXPORT_SYMBOL_GPL(ocxl_link_release); static u64 calculate_cfg_state(bool kernel) { @@ -533,6 +536,7 @@ unlock: mutex_unlock(&spa->spa_lock); return rc; } +EXPORT_SYMBOL_GPL(ocxl_link_add_pe); int ocxl_link_remove_pe(void *link_handle, int pasid) { @@ -601,6 +605,7 @@ unlock: mutex_unlock(&spa->spa_lock); return rc; } +EXPORT_SYMBOL_GPL(ocxl_link_remove_pe); int ocxl_link_irq_alloc(void *link_handle, int *hw_irq, u64 *trigger_addr) { @@ -621,6 +626,7 @@ int ocxl_link_irq_alloc(void *link_handle, int *hw_irq, u64 *trigger_addr) *trigger_addr = addr; return 0; } +EXPORT_SYMBOL_GPL(ocxl_link_irq_alloc); void ocxl_link_free_irq(void *link_handle, int hw_irq) { @@ -629,3 +635,4 @@ void ocxl_link_free_irq(void *link_handle, int hw_irq) pnv_ocxl_free_xive_irq(hw_irq); atomic_inc(&link->irq_available); } +EXPORT_SYMBOL_GPL(ocxl_link_free_irq); diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h index a89b88ac67eb..5d421824afd9 100644 --- a/drivers/misc/ocxl/ocxl_internal.h +++ b/drivers/misc/ocxl/ocxl_internal.h @@ -6,8 +6,8 @@ #include #include #include +#include -#define OCXL_AFU_NAME_SZ (24+1) /* add 1 for NULL termination */ #define MAX_IRQ_PER_LINK 2000 #define MAX_IRQ_PER_CONTEXT MAX_IRQ_PER_LINK @@ -16,38 +16,6 @@ extern struct pci_driver ocxl_pci_driver; -/* - * The following 2 structures are a fairly generic way of representing - * the configuration data for a function and AFU, as read from the - * configuration space. - */ -struct ocxl_afu_config { - u8 idx; - int dvsec_afu_control_pos; - char name[OCXL_AFU_NAME_SZ]; - u8 version_major; - u8 version_minor; - u8 afuc_type; - u8 afum_type; - u8 profile; - u8 global_mmio_bar; - u64 global_mmio_offset; - u32 global_mmio_size; - u8 pp_mmio_bar; - u64 pp_mmio_offset; - u32 pp_mmio_stride; - u8 log_mem_size; - u8 pasid_supported_log; - u16 actag_supported; -}; - -struct ocxl_fn_config { - int dvsec_tl_pos; - int dvsec_function_pos; - int dvsec_afu_info_pos; - s8 max_pasid_log; - s8 max_afu_index; -}; struct ocxl_fn { struct device dev; @@ -135,43 +103,6 @@ extern void ocxl_unregister_afu(struct ocxl_afu *afu); extern int ocxl_file_init(void); extern void ocxl_file_exit(void); -extern int ocxl_config_read_function(struct pci_dev *dev, - struct ocxl_fn_config *fn); - -extern int ocxl_config_check_afu_index(struct pci_dev *dev, - struct ocxl_fn_config *fn, int afu_idx); -extern int ocxl_config_read_afu(struct pci_dev *dev, - struct ocxl_fn_config *fn, - struct ocxl_afu_config *afu, - u8 afu_idx); -extern int ocxl_config_get_pasid_info(struct pci_dev *dev, int *count); -extern void ocxl_config_set_afu_pasid(struct pci_dev *dev, - int afu_control, - int pasid_base, u32 pasid_count_log); -extern int ocxl_config_get_actag_info(struct pci_dev *dev, - u16 *base, u16 *enabled, u16 *supported); -extern void ocxl_config_set_actag(struct pci_dev *dev, int func_dvsec, - u32 tag_first, u32 tag_count); -extern void ocxl_config_set_afu_actag(struct pci_dev *dev, int afu_control, - int actag_base, int actag_count); -extern void ocxl_config_set_afu_state(struct pci_dev *dev, int afu_control, - int enable); -extern int ocxl_config_set_TL(struct pci_dev *dev, int tl_dvsec); -extern int ocxl_config_terminate_pasid(struct pci_dev *dev, int afu_control, - int pasid); - -extern int ocxl_link_setup(struct pci_dev *dev, int PE_mask, - void **link_handle); -extern void ocxl_link_release(struct pci_dev *dev, void *link_handle); -extern int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr, - u64 amr, struct mm_struct *mm, - void (*xsl_err_cb)(void *data, u64 addr, u64 dsisr), - void *xsl_err_data); -extern int ocxl_link_remove_pe(void *link_handle, int pasid); -extern int ocxl_link_irq_alloc(void *link_handle, int *hw_irq, - u64 *addr); -extern void ocxl_link_free_irq(void *link_handle, int hw_irq); - extern int ocxl_pasid_afu_alloc(struct ocxl_fn *fn, u32 size); extern void ocxl_pasid_afu_free(struct ocxl_fn *fn, u32 start, u32 size); extern int ocxl_actag_afu_alloc(struct ocxl_fn *fn, u32 size); -- cgit From 92add22e84788d44e978662ca6bcd585f9ac081e Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 23 Jan 2018 12:31:44 +0100 Subject: ocxl: Add trace points Define a few trace points so that we can use the standard tracing mechanism for debug and/or monitoring. Signed-off-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/afu_irq.c | 5 ++ drivers/misc/ocxl/context.c | 2 + drivers/misc/ocxl/link.c | 11 ++- drivers/misc/ocxl/trace.c | 6 ++ drivers/misc/ocxl/trace.h | 182 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 drivers/misc/ocxl/trace.c create mode 100644 drivers/misc/ocxl/trace.h (limited to 'drivers') diff --git a/drivers/misc/ocxl/afu_irq.c b/drivers/misc/ocxl/afu_irq.c index f40d853de401..e70cfa24577f 100644 --- a/drivers/misc/ocxl/afu_irq.c +++ b/drivers/misc/ocxl/afu_irq.c @@ -4,6 +4,7 @@ #include #include #include "ocxl_internal.h" +#include "trace.h" struct afu_irq { int id; @@ -28,6 +29,7 @@ static irqreturn_t afu_irq_handler(int virq, void *data) { struct afu_irq *irq = (struct afu_irq *) data; + trace_ocxl_afu_irq_receive(virq); if (irq->ev_ctx) eventfd_signal(irq->ev_ctx, 1); return IRQ_HANDLED; @@ -102,6 +104,8 @@ int ocxl_afu_irq_alloc(struct ocxl_context *ctx, u64 *irq_offset) *irq_offset = irq_id_to_offset(ctx, irq->id); + trace_ocxl_afu_irq_alloc(ctx->pasid, irq->id, irq->virq, irq->hw_irq, + *irq_offset); mutex_unlock(&ctx->irq_lock); return 0; @@ -117,6 +121,7 @@ err_unlock: static void afu_irq_free(struct afu_irq *irq, struct ocxl_context *ctx) { + trace_ocxl_afu_irq_free(ctx->pasid, irq->id); if (ctx->mapping) unmap_mapping_range(ctx->mapping, irq_id_to_offset(ctx, irq->id), diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c index 269149490063..909e8807824a 100644 --- a/drivers/misc/ocxl/context.c +++ b/drivers/misc/ocxl/context.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ // Copyright 2017 IBM Corp. #include +#include "trace.h" #include "ocxl_internal.h" struct ocxl_context *ocxl_context_alloc(void) @@ -214,6 +215,7 @@ int ocxl_context_detach(struct ocxl_context *ctx) mutex_lock(&ctx->afu->afu_control_lock); rc = ocxl_config_terminate_pasid(dev, afu_control_pos, ctx->pasid); mutex_unlock(&ctx->afu->afu_control_lock); + trace_ocxl_terminate_pasid(ctx->pasid, rc); if (rc) { /* * If we timeout waiting for the AFU to terminate the diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c index fbca3feec592..f30790582dc0 100644 --- a/drivers/misc/ocxl/link.c +++ b/drivers/misc/ocxl/link.c @@ -7,6 +7,7 @@ #include #include #include "ocxl_internal.h" +#include "trace.h" #define SPA_PASID_BITS 15 @@ -116,8 +117,11 @@ static void ack_irq(struct spa *spa, enum xsl_response r) else WARN(1, "Invalid irq response %d\n", r); - if (reg) + if (reg) { + trace_ocxl_fault_ack(spa->spa_mem, spa->xsl_fault.pe, + spa->xsl_fault.dsisr, spa->xsl_fault.dar, reg); out_be64(spa->reg_tfc, reg); + } } static void xsl_fault_handler_bh(struct work_struct *fault_work) @@ -182,6 +186,7 @@ static irqreturn_t xsl_fault_handler(int irq, void *data) int lpid, pid, tid; read_irq(spa, &dsisr, &dar, &pe_handle); + trace_ocxl_fault(spa->spa_mem, pe_handle, dsisr, dar, -1); WARN_ON(pe_handle > SPA_PE_MASK); pe = spa->spa_mem + pe_handle; @@ -532,6 +537,7 @@ int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr, * the problem. */ mmgrab(mm); + trace_ocxl_context_add(current->pid, spa->spa_mem, pasid, pidr, tidr); unlock: mutex_unlock(&spa->spa_lock); return rc; @@ -577,6 +583,9 @@ int ocxl_link_remove_pe(void *link_handle, int pasid) goto unlock; } + trace_ocxl_context_remove(current->pid, spa->spa_mem, pasid, + be32_to_cpu(pe->pid), be32_to_cpu(pe->tid)); + memset(pe, 0, sizeof(struct ocxl_process_element)); /* * The barrier makes sure the PE is removed from the SPA diff --git a/drivers/misc/ocxl/trace.c b/drivers/misc/ocxl/trace.c new file mode 100644 index 000000000000..1e6947049697 --- /dev/null +++ b/drivers/misc/ocxl/trace.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" +#endif diff --git a/drivers/misc/ocxl/trace.h b/drivers/misc/ocxl/trace.h new file mode 100644 index 000000000000..bcb7ff330c1e --- /dev/null +++ b/drivers/misc/ocxl/trace.h @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017 IBM Corp. +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ocxl + +#if !defined(_TRACE_OCXL_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_OCXL_H + +#include + +DECLARE_EVENT_CLASS(ocxl_context, + TP_PROTO(pid_t pid, void *spa, int pasid, u32 pidr, u32 tidr), + TP_ARGS(pid, spa, pasid, pidr, tidr), + + TP_STRUCT__entry( + __field(pid_t, pid) + __field(void*, spa) + __field(int, pasid) + __field(u32, pidr) + __field(u32, tidr) + ), + + TP_fast_assign( + __entry->pid = pid; + __entry->spa = spa; + __entry->pasid = pasid; + __entry->pidr = pidr; + __entry->tidr = tidr; + ), + + TP_printk("linux pid=%d spa=0x%p pasid=0x%x pidr=0x%x tidr=0x%x", + __entry->pid, + __entry->spa, + __entry->pasid, + __entry->pidr, + __entry->tidr + ) +); + +DEFINE_EVENT(ocxl_context, ocxl_context_add, + TP_PROTO(pid_t pid, void *spa, int pasid, u32 pidr, u32 tidr), + TP_ARGS(pid, spa, pasid, pidr, tidr) +); + +DEFINE_EVENT(ocxl_context, ocxl_context_remove, + TP_PROTO(pid_t pid, void *spa, int pasid, u32 pidr, u32 tidr), + TP_ARGS(pid, spa, pasid, pidr, tidr) +); + +TRACE_EVENT(ocxl_terminate_pasid, + TP_PROTO(int pasid, int rc), + TP_ARGS(pasid, rc), + + TP_STRUCT__entry( + __field(int, pasid) + __field(int, rc) + ), + + TP_fast_assign( + __entry->pasid = pasid; + __entry->rc = rc; + ), + + TP_printk("pasid=0x%x rc=%d", + __entry->pasid, + __entry->rc + ) +); + +DECLARE_EVENT_CLASS(ocxl_fault_handler, + TP_PROTO(void *spa, u64 pe, u64 dsisr, u64 dar, u64 tfc), + TP_ARGS(spa, pe, dsisr, dar, tfc), + + TP_STRUCT__entry( + __field(void *, spa) + __field(u64, pe) + __field(u64, dsisr) + __field(u64, dar) + __field(u64, tfc) + ), + + TP_fast_assign( + __entry->spa = spa; + __entry->pe = pe; + __entry->dsisr = dsisr; + __entry->dar = dar; + __entry->tfc = tfc; + ), + + TP_printk("spa=%p pe=0x%llx dsisr=0x%llx dar=0x%llx tfc=0x%llx", + __entry->spa, + __entry->pe, + __entry->dsisr, + __entry->dar, + __entry->tfc + ) +); + +DEFINE_EVENT(ocxl_fault_handler, ocxl_fault, + TP_PROTO(void *spa, u64 pe, u64 dsisr, u64 dar, u64 tfc), + TP_ARGS(spa, pe, dsisr, dar, tfc) +); + +DEFINE_EVENT(ocxl_fault_handler, ocxl_fault_ack, + TP_PROTO(void *spa, u64 pe, u64 dsisr, u64 dar, u64 tfc), + TP_ARGS(spa, pe, dsisr, dar, tfc) +); + +TRACE_EVENT(ocxl_afu_irq_alloc, + TP_PROTO(int pasid, int irq_id, unsigned int virq, int hw_irq, + u64 irq_offset), + TP_ARGS(pasid, irq_id, virq, hw_irq, irq_offset), + + TP_STRUCT__entry( + __field(int, pasid) + __field(int, irq_id) + __field(unsigned int, virq) + __field(int, hw_irq) + __field(u64, irq_offset) + ), + + TP_fast_assign( + __entry->pasid = pasid; + __entry->irq_id = irq_id; + __entry->virq = virq; + __entry->hw_irq = hw_irq; + __entry->irq_offset = irq_offset; + ), + + TP_printk("pasid=0x%x irq_id=%d virq=%u hw_irq=%d irq_offset=0x%llx", + __entry->pasid, + __entry->irq_id, + __entry->virq, + __entry->hw_irq, + __entry->irq_offset + ) +); + +TRACE_EVENT(ocxl_afu_irq_free, + TP_PROTO(int pasid, int irq_id), + TP_ARGS(pasid, irq_id), + + TP_STRUCT__entry( + __field(int, pasid) + __field(int, irq_id) + ), + + TP_fast_assign( + __entry->pasid = pasid; + __entry->irq_id = irq_id; + ), + + TP_printk("pasid=0x%x irq_id=%d", + __entry->pasid, + __entry->irq_id + ) +); + +TRACE_EVENT(ocxl_afu_irq_receive, + TP_PROTO(int virq), + TP_ARGS(virq), + + TP_STRUCT__entry( + __field(int, virq) + ), + + TP_fast_assign( + __entry->virq = virq; + ), + + TP_printk("virq=%d", + __entry->virq + ) +); + +#endif /* _TRACE_OCXL_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace +#include -- cgit From b97f02246e0d12f70249a16f931153b8b5b249bd Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 23 Jan 2018 12:31:45 +0100 Subject: ocxl: Add Makefile and Kconfig OCXL_BASE triggers the platform support needed by the driver. Signed-off-by: Frederic Barrat Signed-off-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/ocxl/Kconfig | 31 +++++++++++++++++++++++++++++++ drivers/misc/ocxl/Makefile | 11 +++++++++++ 4 files changed, 44 insertions(+) create mode 100644 drivers/misc/ocxl/Kconfig create mode 100644 drivers/misc/ocxl/Makefile (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index f1a5c2357b14..0534f338c84a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -508,4 +508,5 @@ source "drivers/misc/mic/Kconfig" source "drivers/misc/genwqe/Kconfig" source "drivers/misc/echo/Kconfig" source "drivers/misc/cxl/Kconfig" +source "drivers/misc/ocxl/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5ca5f64df478..73326d54e246 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o +obj-$(CONFIG_OCXL) += ocxl/ lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o diff --git a/drivers/misc/ocxl/Kconfig b/drivers/misc/ocxl/Kconfig new file mode 100644 index 000000000000..4bbdb0d3c8ee --- /dev/null +++ b/drivers/misc/ocxl/Kconfig @@ -0,0 +1,31 @@ +# +# Open Coherent Accelerator (OCXL) compatible devices +# + +config OCXL_BASE + bool + default n + select PPC_COPRO_BASE + +config OCXL + tristate "OpenCAPI coherent accelerator support" + depends on PPC_POWERNV && PCI && EEH + select OCXL_BASE + default m + help + Select this option to enable the ocxl driver for Open + Coherent Accelerator Processor Interface (OpenCAPI) devices. + + OpenCAPI allows FPGA and ASIC accelerators to be coherently + attached to a CPU over an OpenCAPI link. + + The ocxl driver enables userspace programs to access these + accelerators through devices in /dev/ocxl/. + + For more information, see http://opencapi.org. + + This is not to be confused with the support for IBM CAPI + accelerators (CONFIG_CXL), which are PCI-based instead of a + dedicated OpenCAPI link, and don't follow the same protocol. + + If unsure, say N. diff --git a/drivers/misc/ocxl/Makefile b/drivers/misc/ocxl/Makefile new file mode 100644 index 000000000000..5229dcda8297 --- /dev/null +++ b/drivers/misc/ocxl/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0+ +ccflags-$(CONFIG_PPC_WERROR) += -Werror + +ocxl-y += main.o pci.o config.o file.o pasid.o +ocxl-y += link.o context.o afu_irq.o sysfs.o trace.o +obj-$(CONFIG_OCXL) += ocxl.o + +# For tracepoints to include our trace.h from tracepoint infrastructure: +CFLAGS_trace.o := -I$(src) + +# ccflags-y += -DDEBUG -- cgit From 741ddae6c4c19bf2212ca318777320ae4f76c714 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 23 Jan 2018 12:31:46 +0100 Subject: cxl: Remove support for "Processing accelerators" class The cxl driver currently declares in its table of supported PCI devices the class "Processing accelerators". Therefore it may be called to probe for opencapi devices, which generates errors, as the config space of a cxl device is not compatible with opencapi. So remove support for the generic class, as we now have (at least) two drivers for devices of the same class. Most cxl devices are FPGAs with a PSL which will show a known device ID of 0x477. Other devices are really supported by the cxlflash driver and are already listed in the table. So removing the class is expected to go unnoticed. Signed-off-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 19969ee86d6f..758842f65a1b 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -125,8 +125,6 @@ static const struct pci_device_id cxl_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0601), }, { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0623), }, { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0628), }, - { PCI_DEVICE_CLASS(0x120000, ~0), }, - { } }; MODULE_DEVICE_TABLE(pci, cxl_pci_tbl); -- cgit From 19cfcafd7f0fa7a672f0ac5146e2ff38594497b0 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Jan 2018 15:42:58 +0100 Subject: i2c: davinci: fix the cpufreq transition i2c_davinci_cpufreq_transition() is implemented in a way that will block if it ever gets called while no transfer is in progress. Not only that, but reinit_completion() is never called for xfr_complete. Use the fact that cpufreq uses an srcu_notifier (running in process context) for transitions and that the bus_lock is taken during the call to master_xfer() and simplify the code by removing the transfer completion entirely and protecting i2c_davinci_cpufreq_transition() with i2c_lock/unlock_adapter(). Reported-by: David Lechner Signed-off-by: Bartosz Golaszewski Reviewed-by: Sekhar Nori Tested-by: David Lechner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-davinci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index cb24a3ffdfa2..75d6ab177055 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -139,7 +139,6 @@ struct davinci_i2c_dev { u8 terminate; struct i2c_adapter adapter; #ifdef CONFIG_CPU_FREQ - struct completion xfr_complete; struct notifier_block freq_transition; #endif struct davinci_i2c_platform_data *pdata; @@ -567,9 +566,6 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) } ret = num; -#ifdef CONFIG_CPU_FREQ - complete(&dev->xfr_complete); -#endif out: pm_runtime_mark_last_busy(dev->dev); @@ -717,13 +713,15 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb, struct davinci_i2c_dev *dev; dev = container_of(nb, struct davinci_i2c_dev, freq_transition); + + i2c_lock_adapter(&dev->adapter); if (val == CPUFREQ_PRECHANGE) { - wait_for_completion(&dev->xfr_complete); davinci_i2c_reset_ctrl(dev, 0); } else if (val == CPUFREQ_POSTCHANGE) { i2c_davinci_calc_clk_dividers(dev); davinci_i2c_reset_ctrl(dev, 1); } + i2c_unlock_adapter(&dev->adapter); return 0; } @@ -790,9 +788,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) } init_completion(&dev->cmd_complete); -#ifdef CONFIG_CPU_FREQ - init_completion(&dev->xfr_complete); -#endif + dev->dev = &pdev->dev; dev->irq = irq; dev->pdata = dev_get_platdata(&pdev->dev); -- cgit From fe34fbf93f87e9e0f78eeeb6f21b2fc310cb6080 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Jan 2018 15:45:11 +0100 Subject: i2c: rcar: fix some trivial typos in comments Nothing big, but they get annoying after a while ;) Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index d4b7b5380c29..4159ebcec2bb 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -62,7 +62,7 @@ #define MIE (1 << 3) /* master if enable */ #define TSBE (1 << 2) #define FSB (1 << 1) /* force stop bit */ -#define ESG (1 << 0) /* en startbit gen */ +#define ESG (1 << 0) /* enable start bit gen */ /* ICSSR (also for ICSIER) */ #define GCAR (1 << 6) /* general call received */ @@ -331,7 +331,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); /* - * We don't have a testcase but the HW engineers say that the write order + * We don't have a test case but the HW engineers say that the write order * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since * it didn't cause a drawback for me, let's rather be safe than sorry. */ @@ -489,7 +489,7 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) /* * Try to use DMA to transmit the rest of the data if - * address transfer pashe just finished. + * address transfer phase just finished. */ if (msr & MAT) rcar_i2c_dma(priv); -- cgit From 13d6eb20fc79a1e606307256dad4098375539a09 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 2 Jan 2018 17:11:52 +0800 Subject: i2c: imx-lpi2c: add runtime pm support Add runtime pm support to dynamically manage the clock to avoid enable/disable clock in frequently that can improve the i2c bus transfer performance. And use pm_runtime_force_suspend/resume() instead of lpi2c_imx_suspend/resume(). Signed-off-by: Fugang Duan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx-lpi2c.c | 68 ++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index e86801a63120..e6da2c7a9a3e 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -90,6 +91,8 @@ #define FAST_PLUS_MAX_BITRATE 3400000 #define HIGHSPEED_MAX_BITRATE 5000000 +#define I2C_PM_TIMEOUT 10 /* ms */ + enum lpi2c_imx_mode { STANDARD, /* 100+Kbps */ FAST, /* 400+Kbps */ @@ -274,8 +277,8 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) unsigned int temp; int ret; - ret = clk_enable(lpi2c_imx->clk); - if (ret) + ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent); + if (ret < 0) return ret; temp = MCR_RST; @@ -284,7 +287,7 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) ret = lpi2c_imx_config(lpi2c_imx); if (ret) - goto clk_disable; + goto rpm_put; temp = readl(lpi2c_imx->base + LPI2C_MCR); temp |= MCR_MEN; @@ -292,8 +295,9 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) return 0; -clk_disable: - clk_disable(lpi2c_imx->clk); +rpm_put: + pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent); + pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent); return ret; } @@ -306,7 +310,8 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx) temp &= ~MCR_MEN; writel(temp, lpi2c_imx->base + LPI2C_MCR); - clk_disable(lpi2c_imx->clk); + pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent); + pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent); return 0; } @@ -606,22 +611,31 @@ static int lpi2c_imx_probe(struct platform_device *pdev) return ret; } + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + temp = readl(lpi2c_imx->base + LPI2C_PARAM); lpi2c_imx->txfifosize = 1 << (temp & 0x0f); lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); - clk_disable(lpi2c_imx->clk); - ret = i2c_add_adapter(&lpi2c_imx->adapter); if (ret) - goto clk_unprepare; + goto rpm_disable; + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n"); return 0; -clk_unprepare: - clk_unprepare(lpi2c_imx->clk); +rpm_disable: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return ret; } @@ -632,28 +646,48 @@ static int lpi2c_imx_remove(struct platform_device *pdev) i2c_del_adapter(&lpi2c_imx->adapter); - clk_unprepare(lpi2c_imx->clk); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return 0; } #ifdef CONFIG_PM_SLEEP -static int lpi2c_imx_suspend(struct device *dev) +static int lpi2c_runtime_suspend(struct device *dev) { + struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); + + clk_disable_unprepare(lpi2c_imx->clk); pinctrl_pm_select_sleep_state(dev); return 0; } -static int lpi2c_imx_resume(struct device *dev) +static int lpi2c_runtime_resume(struct device *dev) { + struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); + int ret; + pinctrl_pm_select_default_state(dev); + ret = clk_prepare_enable(lpi2c_imx->clk); + if (ret) { + dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret); + return ret; + } return 0; } -#endif -static SIMPLE_DEV_PM_OPS(imx_lpi2c_pm, lpi2c_imx_suspend, lpi2c_imx_resume); +static const struct dev_pm_ops lpi2c_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend, + lpi2c_runtime_resume, NULL) +}; +#define IMX_LPI2C_PM (&lpi2c_pm_ops) +#else +#define IMX_LPI2C_PM NULL +#endif static struct platform_driver lpi2c_imx_driver = { .probe = lpi2c_imx_probe, @@ -661,7 +695,7 @@ static struct platform_driver lpi2c_imx_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = lpi2c_imx_of_match, - .pm = &imx_lpi2c_pm, + .pm = IMX_LPI2C_PM, }, }; -- cgit From 931b18e92cd035353644fcefa3626a65c74fa799 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Mon, 20 Nov 2017 22:54:12 +0800 Subject: i2c: meson: add configurable divider factors This patch try to add support for I2C controller in Meson-AXG SoC, Due to the IP changes between I2C controller, we need to introduce a compatible data to make the divider factor configurable. Reviewed-by: Neil Armstrong Signed-off-by: Jian Hu Signed-off-by: Yixun Lan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 88d15b92ec35..37c4aa76f37a 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,10 @@ enum { STATE_WRITE, }; +struct meson_i2c_data { + unsigned char div_factor; +}; + /** * struct meson_i2c - Meson I2C device private data * @@ -93,6 +98,8 @@ struct meson_i2c { struct completion done; u32 tokens[2]; int num_tokens; + + const struct meson_i2c_data *data; }; static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, @@ -128,7 +135,7 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) unsigned long clk_rate = clk_get_rate(i2c->clk); unsigned int div; - div = DIV_ROUND_UP(clk_rate, freq * 4); + div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor); /* clock divider has 12 bits */ if (div >= (1 << 12)) { @@ -376,6 +383,9 @@ static int meson_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_completion(&i2c->done); + i2c->data = (const struct meson_i2c_data *) + of_device_get_match_data(&pdev->dev); + i2c->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "can't get device clock\n"); @@ -440,11 +450,25 @@ static int meson_i2c_remove(struct platform_device *pdev) return 0; } +static const struct meson_i2c_data i2c_meson6_data = { + .div_factor = 4, +}; + +static const struct meson_i2c_data i2c_gxbb_data = { + .div_factor = 4, +}; + +static const struct meson_i2c_data i2c_axg_data = { + .div_factor = 3, +}; + static const struct of_device_id meson_i2c_match[] = { - { .compatible = "amlogic,meson6-i2c" }, - { .compatible = "amlogic,meson-gxbb-i2c" }, - { }, + { .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data }, + { .compatible = "amlogic,meson-gxbb-i2c", .data = &i2c_gxbb_data }, + { .compatible = "amlogic,meson-axg-i2c", .data = &i2c_axg_data }, + {}, }; + MODULE_DEVICE_TABLE(of, meson_i2c_match); static struct platform_driver meson_i2c_driver = { -- cgit From 7e4c9d9e508f63b6371e4fcffc882e712c8307ad Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Wed, 24 Jan 2018 15:05:14 +0800 Subject: i2c: meson: update doc description to fix build warnings Add description for 'data' parameter and drop unused 'irq' memeber. Here is the warnings: drivers/i2c/busses/i2c-meson.c:103: warning: No description found for parameter 'data' drivers/i2c/busses/i2c-meson.c:103: warning: Excess struct member 'irq' description in 'meson_i2c' Reported-by: Wolfram Sang Signed-off-by: Yixun Lan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 37c4aa76f37a..90f5d0407d73 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -69,7 +69,6 @@ struct meson_i2c_data { * @dev: Pointer to device structure * @regs: Base address of the device memory mapped registers * @clk: Pointer to clock structure - * @irq: IRQ number * @msg: Pointer to the current I2C message * @state: Current state in the driver state machine * @last: Flag set for the last message in the transfer @@ -80,6 +79,7 @@ struct meson_i2c_data { * @done: Completion used to wait for transfer termination * @tokens: Sequence of tokens to be written to the device * @num_tokens: Number of tokens + * @data: Pointer to the controlller's platform data */ struct meson_i2c { struct i2c_adapter adap; -- cgit From 4be49b5d652e8b81ba8d019727ebd8cafd7ab4ac Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 23 Jan 2018 11:38:27 -0600 Subject: i2c: mxs: use true and false for boolean values Assign true or false to boolean variables instead of an integer value. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index d4e8f1954f23..e617bd600794 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -181,7 +181,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); if (msg->flags & I2C_M_RD) { - i2c->dma_read = 1; + i2c->dma_read = true; i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; /* @@ -239,7 +239,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, goto read_init_dma_fail; } } else { - i2c->dma_read = 0; + i2c->dma_read = false; i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; /* -- cgit From a9e94bb80ea6d53745eb5ca86597696735565fb3 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 16 Jan 2018 17:35:38 +0100 Subject: i2c: mv64xxx: Remove useless test before clk_disable_unprepare clk_disable_unprepare() already checks that the clock pointer is valid. No need to test it before calling it. Signed-off-by: Gregory CLEMENT Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a832c45276a4..f69066266faa 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -950,9 +950,7 @@ exit_free_irq: exit_reset: reset_control_assert(drv_data->rstc); exit_clk: - /* Not all platforms have a clk */ - if (!IS_ERR(drv_data->clk)) - clk_disable_unprepare(drv_data->clk); + clk_disable_unprepare(drv_data->clk); return rc; } @@ -965,9 +963,7 @@ mv64xxx_i2c_remove(struct platform_device *dev) i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); reset_control_assert(drv_data->rstc); - /* Not all platforms have a clk */ - if (!IS_ERR(drv_data->clk)) - clk_disable_unprepare(drv_data->clk); + clk_disable_unprepare(drv_data->clk); return 0; } -- cgit From 1534156e999735fe0befad958e1447600c0c20e7 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 16 Jan 2018 17:35:39 +0100 Subject: i2c: mv64xxx: Fix clock resource by adding an optional bus clock On Armada 7K/8K we need to explicitly enable the bus clock. The bus clock is optional because not all the SoCs need them but at least for Armada 7K/8K it is actually mandatory. The binding documentation is updating accordingly. Signed-off-by: Gregory CLEMENT Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index f69066266faa..440fe4a96e68 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -135,6 +135,7 @@ struct mv64xxx_i2c_data { u32 freq_m; u32 freq_n; struct clk *clk; + struct clk *reg_clk; wait_queue_head_t waitq; spinlock_t lock; struct i2c_msg *msg; @@ -894,13 +895,20 @@ mv64xxx_i2c_probe(struct platform_device *pd) init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); - /* Not all platforms have a clk */ + /* Not all platforms have clocks */ drv_data->clk = devm_clk_get(&pd->dev, NULL); if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER) return -EPROBE_DEFER; if (!IS_ERR(drv_data->clk)) clk_prepare_enable(drv_data->clk); + drv_data->reg_clk = devm_clk_get(&pd->dev, "reg"); + if (IS_ERR(drv_data->reg_clk) && + PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!IS_ERR(drv_data->reg_clk)) + clk_prepare_enable(drv_data->reg_clk); + drv_data->irq = platform_get_irq(pd, 0); if (pdata) { @@ -950,6 +958,7 @@ exit_free_irq: exit_reset: reset_control_assert(drv_data->rstc); exit_clk: + clk_disable_unprepare(drv_data->reg_clk); clk_disable_unprepare(drv_data->clk); return rc; @@ -963,6 +972,7 @@ mv64xxx_i2c_remove(struct platform_device *dev) i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); reset_control_assert(drv_data->rstc); + clk_disable_unprepare(drv_data->reg_clk); clk_disable_unprepare(drv_data->clk); return 0; -- cgit From 856e1eb9bdd4bd703907925be112519ff65d991f Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Fri, 5 Jan 2018 10:45:47 -0600 Subject: PCI/AER: Add uevents in AER and EEH error/resume Devices can go offline when erors reported. This patch adds a change to the kernel object and lets udev know of error. When device resumes, a change is also set reporting device as online. Therefore, EEH and AER events are better propagated to user space for PCI devices in all arches. Signed-off-by: Bryant G. Ly Signed-off-by: Juan J. Alvarez Acked-by: Bjorn Helgaas Acked-by: Russell Currey Signed-off-by: Michael Ellerman --- drivers/pci/pcie/aer/aerdrv_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 744805232155..8d7448063fd1 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -278,6 +278,7 @@ static int report_error_detected(struct pci_dev *dev, void *data) } else { err_handler = dev->driver->err_handler; vote = err_handler->error_detected(dev, result_data->state); + pci_uevent_ers(dev, PCI_ERS_RESULT_NONE); } result_data->result = merge_result(result_data->result, vote); @@ -341,6 +342,7 @@ static int report_resume(struct pci_dev *dev, void *data) err_handler = dev->driver->err_handler; err_handler->resume(dev); + pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED); out: device_unlock(&dev->dev); return 0; @@ -541,6 +543,7 @@ static void do_recovery(struct pci_dev *dev, int severity) return; failed: + pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT); /* TODO: Should kernel panic here? */ dev_info(&dev->dev, "AER: Device recovery failed\n"); } -- cgit From f2be6295684b0fe879a824ac97479799e760b7e9 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 28 Nov 2016 21:29:07 +0100 Subject: macintosh/adb: Properly mark continued kernel messages Use pr_cont where appropriate, and switch to pr_foo throughout. Additionally, lower messages in adb_probe_task to debug level. Signed-off-by: Andreas Schwab [mpe: Clean up whitespace slightly] Signed-off-by: Michael Ellerman --- drivers/macintosh/adb.c | 24 ++++++++++---------- drivers/macintosh/adbhid.c | 55 +++++++++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 289800b5235d..4c8097e0e6fe 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -203,18 +203,17 @@ static int adb_scan_bus(void) } /* Now fill in the handler_id field of the adb_handler entries. */ - printk(KERN_DEBUG "adb devices:"); + pr_debug("adb devices:\n"); for (i = 1; i < 16; i++) { if (adb_handler[i].original_address == 0) continue; adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, (i << 4) | 0xf); adb_handler[i].handler_id = req.reply[2]; - printk(" [%d]: %d %x", i, adb_handler[i].original_address, - adb_handler[i].handler_id); + pr_debug(" [%d]: %d %x\n", i, adb_handler[i].original_address, + adb_handler[i].handler_id); devmask |= 1 << i; } - printk("\n"); return devmask; } @@ -225,9 +224,9 @@ static int adb_scan_bus(void) static int adb_probe_task(void *x) { - printk(KERN_INFO "adb: starting probe task...\n"); + pr_debug("adb: starting probe task...\n"); do_adb_reset_bus(); - printk(KERN_INFO "adb: finished probe task...\n"); + pr_debug("adb: finished probe task...\n"); up(&adb_probe_mutex); @@ -337,7 +336,7 @@ static int __init adb_init(void) adb_controller->init()) adb_controller = NULL; if (adb_controller == NULL) { - printk(KERN_WARNING "Warning: no ADB interface detected\n"); + pr_warn("Warning: no ADB interface detected\n"); } else { #ifdef CONFIG_PPC if (of_machine_is_compatible("AAPL,PowerBook1998") || @@ -480,8 +479,7 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids, (!handler_id || (handler_id == adb_handler[i].handler_id) || try_handler_change(i, handler_id))) { if (adb_handler[i].handler != 0) { - printk(KERN_ERR - "Two handlers for ADB device %d\n", + pr_err("Two handlers for ADB device %d\n", default_id); continue; } @@ -535,10 +533,10 @@ adb_input(unsigned char *buf, int nb, int autopoll) id = buf[0] >> 4; if (dump_adb_input) { - printk(KERN_INFO "adb packet: "); + pr_info("adb packet: "); for (i = 0; i < nb; ++i) - printk(" %x", buf[i]); - printk(", id = %d\n", id); + pr_cont(" %x", buf[i]); + pr_cont(", id = %d\n", id); } write_lock_irqsave(&adb_handler_lock, flags); handler = adb_handler[id].handler; @@ -884,7 +882,7 @@ static void __init adbdev_init(void) { if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) { - printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); + pr_err("adb: unable to get major %d\n", ADB_MAJOR); return; } diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index e091193104f7..a261892c03b3 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -268,7 +268,7 @@ adbhid_keyboard_input(unsigned char *data, int nb, int apoll) int id = (data[0] >> 4) & 0x0f; if (!adbhid[id]) { - printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n", + pr_err("ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n", id, data[0], data[1], data[2], data[3]); return; } @@ -320,8 +320,7 @@ adbhid_input_keycode(int id, int scancode, int repeat) ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE; } } else { - printk(KERN_INFO "Spurious caps lock event " - "(scancode 0xff).\n"); + pr_info("Spurious caps lock event (scancode 0xff).\n"); } } } @@ -397,8 +396,8 @@ adbhid_input_keycode(int id, int scancode, int repeat) input_report_key(adbhid[id]->input, key, !up_flag); input_sync(adbhid[id]->input); } else - printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, - up_flag ? "released" : "pressed"); + pr_info("Unhandled ADB key (scancode %#02x) %s.\n", keycode, + up_flag ? "released" : "pressed"); } @@ -408,7 +407,7 @@ adbhid_mouse_input(unsigned char *data, int nb, int autopoll) int id = (data[0] >> 4) & 0x0f; if (!adbhid[id]) { - printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + pr_err("ADB HID on ID %d not yet registered\n", id); return; } @@ -506,7 +505,7 @@ adbhid_buttons_input(unsigned char *data, int nb, int autopoll) int id = (data[0] >> 4) & 0x0f; if (!adbhid[id]) { - printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + pr_err("ADB HID on ID %d not yet registered\n", id); return; } @@ -534,8 +533,8 @@ adbhid_buttons_input(unsigned char *data, int nb, int autopoll) break; default: - printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", - data[0], data[1], data[2], data[3]); + pr_info("Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); break; } } @@ -609,14 +608,14 @@ adbhid_buttons_input(unsigned char *data, int nb, int autopoll) break; default: - printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", - data[0], data[1], data[2], data[3]); + pr_info("Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); break; } break; default: - printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", - data[0], data[1], data[2], data[3]); + pr_info("Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); break; } } @@ -760,7 +759,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id, int i; if (adbhid[id]) { - printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id); + pr_err("Trying to reregister ADB HID on ID %d\n", id); return -EEXIST; } @@ -799,24 +798,24 @@ adbhid_input_register(int id, int default_id, int original_handler_id, memcpy(hid->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); - printk(KERN_INFO "Detected ADB keyboard, type "); + pr_info("Detected ADB keyboard, type "); switch (original_handler_id) { default: - printk(".\n"); + pr_cont(".\n"); input_dev->id.version = ADB_KEYBOARD_UNKNOWN; break; case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: case 0xC0: case 0xC3: case 0xC6: - printk("ANSI.\n"); + pr_cont("ANSI.\n"); input_dev->id.version = ADB_KEYBOARD_ANSI; break; case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: case 0xC4: case 0xC7: - printk("ISO, swapping keys.\n"); + pr_cont("ISO, swapping keys.\n"); input_dev->id.version = ADB_KEYBOARD_ISO; i = hid->keycode[10]; hid->keycode[10] = hid->keycode[50]; @@ -825,7 +824,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id, case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: - printk("JIS.\n"); + pr_cont("JIS.\n"); input_dev->id.version = ADB_KEYBOARD_JIS; break; } @@ -884,7 +883,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id, /* else fall through */ default: - printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n"); + pr_info("Trying to register unknown ADB device to input layer.\n"); err = -ENODEV; goto fail; } @@ -1073,12 +1072,12 @@ adbhid_probe(void) (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) && (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) { if (adb_try_handler_change(id, 0x42)) { - printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); + pr_cont("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); mouse_kind = ADBMOUSE_MACALLY2; } } } - printk("\n"); + pr_cont("\n"); adb_get_infos(id, &default_id, &cur_handler_id); reg |= adbhid_input_reregister(id, default_id, org_handler_id, @@ -1093,12 +1092,12 @@ init_trackpad(int id) struct adb_request req; unsigned char r1_buffer[8]; - printk(" (trackpad)"); + pr_cont(" (trackpad)"); adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, ADB_READREG(id,1)); if (req.reply_len < 8) - printk("bad length for reg. 1\n"); + pr_cont("bad length for reg. 1\n"); else { memcpy(r1_buffer, &req.reply[1], 8); @@ -1146,7 +1145,7 @@ init_trackball(int id) { struct adb_request req; - printk(" (trackman/mouseman)"); + pr_cont(" (trackman/mouseman)"); adb_request(&req, NULL, ADBREQ_SYNC, 3, ADB_WRITEREG(id,1), 00,0x81); @@ -1178,7 +1177,7 @@ init_turbomouse(int id) { struct adb_request req; - printk(" (TurboMouse 5)"); + pr_cont(" (TurboMouse 5)"); adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); @@ -1214,7 +1213,7 @@ init_microspeed(int id) { struct adb_request req; - printk(" (Microspeed/MacPoint or compatible)"); + pr_cont(" (Microspeed/MacPoint or compatible)"); adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); @@ -1254,7 +1253,7 @@ init_ms_a3(int id) { struct adb_request req; - printk(" (Mouse Systems A3 Mouse, or compatible)"); + pr_cont(" (Mouse Systems A3 Mouse, or compatible)"); adb_request(&req, NULL, ADBREQ_SYNC, 3, ADB_WRITEREG(id, 0x2), 0x00, -- cgit From 5b8b58063029f02da573120ef4dc9079822e3cda Mon Sep 17 00:00:00 2001 From: Stewart Smith Date: Tue, 2 Aug 2016 11:50:16 +1000 Subject: rtc-opal: Fix handling of firmware error codes, prevent busy loops According to the OPAL docs: skiboot-5.2.5/doc/opal-api/opal-rtc-read-3.txt skiboot-5.2.5/doc/opal-api/opal-rtc-write-4.txt OPAL_HARDWARE may be returned from OPAL_RTC_READ or OPAL_RTC_WRITE and this indicates either a transient or permanent error. Prior to this patch, Linux was not dealing with OPAL_HARDWARE being a permanent error particularly well, in that you could end up in a busy loop. This was not too hard to trigger on an AMI BMC based OpenPOWER machine doing a continuous "ipmitool mc reset cold" to the BMC, the result of that being that we'd get stuck in an infinite loop in opal_get_rtc_time(). We now retry a few times before returning the error higher up the stack. Fixes: 16b1d26e77b1 ("rtc/tpo: Driver to support rtc and wakeup on PowerNV platform") Cc: stable@vger.kernel.org # v3.19+ Signed-off-by: Stewart Smith Signed-off-by: Michael Ellerman --- drivers/rtc/rtc-opal.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index e2a946c0e667..304e891e35fc 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -58,6 +58,7 @@ static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms) static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) { long rc = OPAL_BUSY; + int retries = 10; u32 y_m_d; u64 h_m_s_ms; __be32 __y_m_d; @@ -67,8 +68,11 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); if (rc == OPAL_BUSY_EVENT) opal_poll_events(NULL); - else + else if (retries-- && (rc == OPAL_HARDWARE + || rc == OPAL_INTERNAL_ERROR)) msleep(10); + else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) + break; } if (rc != OPAL_SUCCESS) @@ -84,6 +88,7 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm) { long rc = OPAL_BUSY; + int retries = 10; u32 y_m_d = 0; u64 h_m_s_ms = 0; @@ -92,8 +97,11 @@ static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm) rc = opal_rtc_write(y_m_d, h_m_s_ms); if (rc == OPAL_BUSY_EVENT) opal_poll_events(NULL); - else + else if (retries-- && (rc == OPAL_HARDWARE + || rc == OPAL_INTERNAL_ERROR)) msleep(10); + else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) + break; } return rc == OPAL_SUCCESS ? 0 : -EIO; -- cgit From 4f256d561447c6e1bf8b70e19daae08da4279f1c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 23 Jan 2018 19:42:28 -0600 Subject: macintosh: change some data types from int to bool Change the data type of the following variables from int to bool across all macintosh drivers: started slots_started pm121_started wf_smu_started Some of these issues were detected with the help of Coccinelle. Suggested-by: Michael Ellerman Signed-off-by: Gustavo A. R. Silva Signed-off-by: Michael Ellerman --- drivers/macintosh/therm_adt746x.c | 4 ++-- drivers/macintosh/windfarm_pm112.c | 8 ++++---- drivers/macintosh/windfarm_pm121.c | 5 +++-- drivers/macintosh/windfarm_pm72.c | 2 +- drivers/macintosh/windfarm_pm81.c | 5 +++-- drivers/macintosh/windfarm_pm91.c | 5 +++-- drivers/macintosh/windfarm_rm31.c | 2 +- 7 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index f433521a6f9d..d7cd5afa38cd 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -230,7 +230,7 @@ static void update_fans_speed (struct thermostat *th) /* we don't care about local sensor, so we start at sensor 1 */ for (i = 1; i < 3; i++) { - int started = 0; + bool started = false; int fan_number = (th->type == ADT7460 && i == 2); int var = th->temps[i] - th->limits[i]; @@ -243,7 +243,7 @@ static void update_fans_speed (struct thermostat *th) if (abs(var - th->last_var[fan_number]) < 2) continue; - started = 1; + started = true; new_speed = fan_speed + ((var-1)*step); if (new_speed < fan_speed) diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index 96d16fca68b2..fec91db1142e 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -96,14 +96,14 @@ static int cpu_last_target; static struct wf_pid_state backside_pid; static int backside_tick; static struct wf_pid_state slots_pid; -static int slots_started; +static bool slots_started; static struct wf_pid_state drive_bay_pid; static int drive_bay_tick; static int nr_cores; static int have_all_controls; static int have_all_sensors; -static int started; +static bool started; static int failure_state; #define FAILURE_SENSOR 1 @@ -462,7 +462,7 @@ static void slots_fan_tick(void) /* first time; initialize things */ printk(KERN_INFO "windfarm: Slots control loop started.\n"); wf_pid_init(&slots_pid, &slots_param); - slots_started = 1; + slots_started = true; } err = slots_power->ops->get_value(slots_power, &power); @@ -506,7 +506,7 @@ static void pm112_tick(void) int i, last_failure; if (!started) { - started = 1; + started = true; printk(KERN_INFO "windfarm: CPUs control loops started.\n"); for (i = 0; i < nr_cores; ++i) { if (create_cpu_loop(i) < 0) { diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index b350fb86ff08..4d72d8f58cb6 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c @@ -246,7 +246,8 @@ enum { static struct wf_control *controls[N_CONTROLS] = {}; /* Set to kick the control loop into life */ -static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started; +static int pm121_all_controls_ok, pm121_all_sensors_ok; +static bool pm121_started; enum { FAILURE_FAN = 1 << 0, @@ -806,7 +807,7 @@ static void pm121_tick(void) pm121_create_sys_fans(i); pm121_create_cpu_fans(); - pm121_started = 1; + pm121_started = true; } /* skipping ticks */ diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c index e88cfb36a74d..833021508c05 100644 --- a/drivers/macintosh/windfarm_pm72.c +++ b/drivers/macintosh/windfarm_pm72.c @@ -611,7 +611,7 @@ static void pm72_tick(void) int i, last_failure; if (!started) { - started = 1; + started = true; printk(KERN_INFO "windfarm: CPUs control loops started.\n"); for (i = 0; i < nr_chips; ++i) { if (cpu_setup_pid(i) < 0) { diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 93faf298a3c5..d9ea45581b9e 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -140,7 +140,8 @@ static struct wf_control *fan_system; static struct wf_control *cpufreq_clamp; /* Set to kick the control loop into life */ -static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started; +static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok; +static bool wf_smu_started; /* Failure handling.. could be nicer */ #define FAILURE_FAN 0x01 @@ -549,7 +550,7 @@ static void wf_smu_tick(void) DBG("wf: creating control loops !\n"); wf_smu_create_sys_fans(); wf_smu_create_cpu_fans(); - wf_smu_started = 1; + wf_smu_started = true; } /* Skipping ticks */ diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 81fdf40c5b82..7fd73dcb2b0a 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -75,7 +75,8 @@ static struct wf_control *fan_slots; static struct wf_control *cpufreq_clamp; /* Set to kick the control loop into life */ -static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started; +static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok; +static bool wf_smu_started; static bool wf_smu_overtemp; /* Failure handling.. could be nicer */ @@ -467,7 +468,7 @@ static void wf_smu_tick(void) wf_smu_create_drive_fans(); wf_smu_create_slots_fans(); wf_smu_create_cpu_fans(); - wf_smu_started = 1; + wf_smu_started = true; } /* Skipping ticks */ diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c index a0cd9c7f9835..9ce87cc0597f 100644 --- a/drivers/macintosh/windfarm_rm31.c +++ b/drivers/macintosh/windfarm_rm31.c @@ -514,7 +514,7 @@ static void rm31_tick(void) int i, last_failure; if (!started) { - started = 1; + started = true; printk(KERN_INFO "windfarm: CPUs control loops started.\n"); for (i = 0; i < nr_chips; ++i) { if (cpu_setup_pid(i) < 0) { -- cgit From 516c32f64f144721ca05b881737e4425932827c5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 23 Jan 2018 19:48:46 -0600 Subject: macintosh/ams-input: Use true and false for boolean values Assign true or false to boolean variables instead of an integer value. This issue was detected with the help of Coccinelle Signed-off-by: Gustavo A. R. Silva Reviewed-by: Michael Hanselmann Signed-off-by: Michael Ellerman --- drivers/macintosh/ams/ams-input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/ams/ams-input.c b/drivers/macintosh/ams/ams-input.c index 2edae7dfcab2..fe248f6a30c1 100644 --- a/drivers/macintosh/ams/ams-input.c +++ b/drivers/macintosh/ams/ams-input.c @@ -91,7 +91,7 @@ static int ams_input_enable(void) return error; } - joystick = 1; + joystick = true; return 0; } @@ -104,7 +104,7 @@ static void ams_input_disable(void) ams_info.idev = NULL; } - joystick = 0; + joystick = false; } static ssize_t ams_input_show_joystick(struct device *dev, -- cgit From 140eb5227767c6754742020a16d2691222b9c19b Mon Sep 17 00:00:00 2001 From: Doug Meyer Date: Tue, 17 Oct 2017 13:22:53 -0700 Subject: NTB: ntb_hw_switchtec: Fix peer BAR bug in switchtec_ntb_init_shared_mw This resolves a bug which may incorrectly configure the peer host's LUT for shared memory window access. The code was using the local host's first BAR number, rather than the peer hosts's first BAR number, to determine what peer NT control register to program. The bug will cause the Switchtec NTB link to work only if both peers have the same first NTB BAR configured. In all other configurations, the link will not come up, failing silently. When both hosts have the same first BAR, the configuration works only because the first BAR numbers happent to be the same. When the hosts do not have the same first BAR, then the LUT translation will not be configured in the correct peer LUT and will not give the peer the shared memory window access required for the link to operate. Signed-off-by: Doug Meyer Reviewed-by: Logan Gunthorpe Fixes: 678784a44ae8 ("NTB: switchtec_ntb: Initialize hardware for memory windows") Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index afe8ed6f3b23..ca0334a6b759 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -964,7 +964,8 @@ static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) { struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; - int bar = sndev->direct_mw_to_bar[0]; + int self_bar = sndev->direct_mw_to_bar[0]; + int peer_bar = sndev->peer_direct_mw_to_bar[0]; u32 ctl_val; int rc; @@ -985,12 +986,12 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) if (rc) goto unalloc_and_exit; - ctl_val = ioread32(&ctl->bar_entry[bar].ctl); + ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl); ctl_val &= 0xFF; ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; ctl_val |= ilog2(LUT_SIZE) << 8; ctl_val |= (sndev->nr_lut_mw - 1) << 14; - iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); + iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl); iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | sndev->self_shared_dma), @@ -1009,7 +1010,7 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) goto unalloc_and_exit; } - sndev->peer_shared = pci_iomap(sndev->stdev->pdev, bar, LUT_SIZE); + sndev->peer_shared = pci_iomap(sndev->stdev->pdev, self_bar, LUT_SIZE); if (!sndev->peer_shared) { rc = -ENOMEM; goto unalloc_and_exit; -- cgit From 0ed08f829b10531c35887fd781d80ef3bfbb1cd9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Nov 2017 15:20:38 +0100 Subject: ntb: remove unneeded DRIVER_LICENSE #defines There is no need to #define the license of the driver, just put it in the MODULE_LICENSE() line directly as a text string. This allows tools that check that the module license matches the source code license to work properly, as there is no need to unwind the unneeded dereference, especially when the string is defined just a few lines above the usage of it. Reported-and-reviewed-by: Philippe Ombredanne Signed-off-by: Greg Kroah-Hartman Cc: Dave Jiang Cc: Allen Hubbe Cc: Gary R Hook Cc: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/ntb.c | 3 +-- drivers/ntb/test/ntb_perf.c | 3 +-- drivers/ntb/test/ntb_pingpong.c | 3 +-- drivers/ntb/test/ntb_tool.c | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c index 03b80d89b980..bdcd59b13c1f 100644 --- a/drivers/ntb/ntb.c +++ b/drivers/ntb/ntb.c @@ -63,12 +63,11 @@ #define DRIVER_NAME "ntb" #define DRIVER_DESCRIPTION "PCIe NTB Driver Framework" -#define DRIVER_LICENSE "Dual BSD/GPL" #define DRIVER_VERSION "1.0" #define DRIVER_RELDATE "24 March 2015" #define DRIVER_AUTHOR "Allen Hubbe " -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESCRIPTION); diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c index 427112cf101a..6f6c602d04af 100644 --- a/drivers/ntb/test/ntb_perf.c +++ b/drivers/ntb/test/ntb_perf.c @@ -63,7 +63,6 @@ #define DRIVER_NAME "ntb_perf" #define DRIVER_DESCRIPTION "PCIe NTB Performance Measurement Tool" -#define DRIVER_LICENSE "Dual BSD/GPL" #define DRIVER_VERSION "1.0" #define DRIVER_AUTHOR "Dave Jiang " @@ -78,7 +77,7 @@ #define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */ #define PIDX NTB_DEF_PEER_IDX -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESCRIPTION); diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c index 3f5a92bae6f8..e700873e03fb 100644 --- a/drivers/ntb/test/ntb_pingpong.c +++ b/drivers/ntb/test/ntb_pingpong.c @@ -68,12 +68,11 @@ #define DRIVER_NAME "ntb_pingpong" #define DRIVER_DESCRIPTION "PCIe NTB Simple Pingpong Client" -#define DRIVER_LICENSE "Dual BSD/GPL" #define DRIVER_VERSION "1.0" #define DRIVER_RELDATE "24 March 2015" #define DRIVER_AUTHOR "Allen Hubbe " -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESCRIPTION); diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c index 91526a986caa..e490bbc8726c 100644 --- a/drivers/ntb/test/ntb_tool.c +++ b/drivers/ntb/test/ntb_tool.c @@ -109,12 +109,11 @@ #define DRIVER_NAME "ntb_tool" #define DRIVER_DESCRIPTION "PCIe NTB Debugging Tool" -#define DRIVER_LICENSE "Dual BSD/GPL" #define DRIVER_VERSION "1.0" #define DRIVER_RELDATE "22 April 2015" #define DRIVER_AUTHOR "Allen Hubbe " -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESCRIPTION); -- cgit From 3f7756728ef4b0155e4f42d6b8a862dd7c38a9c2 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 20 Nov 2017 10:24:08 -0700 Subject: ntb: remove Intel Atom NTB driver support Removing dead code since this is not being used. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 309 +----------------------------------- drivers/ntb/hw/intel/ntb_hw_intel.h | 58 ------- 2 files changed, 4 insertions(+), 363 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 4de074a86073..341a3d5baa3f 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -74,12 +74,6 @@ MODULE_AUTHOR("Intel Corporation"); #define bar0_off(base, bar) ((base) + ((bar) << 2)) #define bar2_off(base, bar) bar0_off(base, (bar) - 2) -static const struct intel_ntb_reg atom_reg; -static const struct intel_ntb_alt_reg atom_pri_reg; -static const struct intel_ntb_alt_reg atom_sec_reg; -static const struct intel_ntb_alt_reg atom_b2b_reg; -static const struct intel_ntb_xlat_reg atom_pri_xlat; -static const struct intel_ntb_xlat_reg atom_sec_xlat; static const struct intel_ntb_reg xeon_reg; static const struct intel_ntb_alt_reg xeon_pri_reg; static const struct intel_ntb_alt_reg xeon_sec_reg; @@ -184,15 +178,6 @@ static inline void _iowrite64(u64 val, void __iomem *mmio) #endif #endif -static inline int pdev_is_atom(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: - return 1; - } - return 0; -} - static inline int pdev_is_xeon(struct pci_dev *pdev) { switch (pdev->device) { @@ -1006,8 +991,7 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, { struct intel_ntb_dev *ndev = filp->private_data; - if (pdev_is_xeon(ndev->ntb.pdev) || - pdev_is_atom(ndev->ntb.pdev)) + if (pdev_is_xeon(ndev->ntb.pdev)) return ndev_ntb_debugfs_read(filp, ubuf, count, offp); else if (pdev_is_skx_xeon(ndev->ntb.pdev)) return ndev_ntb3_debugfs_read(filp, ubuf, count, offp); @@ -1439,242 +1423,6 @@ static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, ndev->peer_reg->spad); } -/* ATOM */ - -static u64 atom_db_ioread(void __iomem *mmio) -{ - return ioread64(mmio); -} - -static void atom_db_iowrite(u64 bits, void __iomem *mmio) -{ - iowrite64(bits, mmio); -} - -static int atom_poll_link(struct intel_ntb_dev *ndev) -{ - u32 ntb_ctl; - - ntb_ctl = ioread32(ndev->self_mmio + ATOM_NTBCNTL_OFFSET); - - if (ntb_ctl == ndev->ntb_ctl) - return 0; - - ndev->ntb_ctl = ntb_ctl; - - ndev->lnk_sta = ioread32(ndev->self_mmio + ATOM_LINK_STATUS_OFFSET); - - return 1; -} - -static int atom_link_is_up(struct intel_ntb_dev *ndev) -{ - return ATOM_NTB_CTL_ACTIVE(ndev->ntb_ctl); -} - -static int atom_link_is_err(struct intel_ntb_dev *ndev) -{ - if (ioread32(ndev->self_mmio + ATOM_LTSSMSTATEJMP_OFFSET) - & ATOM_LTSSMSTATEJMP_FORCEDETECT) - return 1; - - if (ioread32(ndev->self_mmio + ATOM_IBSTERRRCRVSTS0_OFFSET) - & ATOM_IBIST_ERR_OFLOW) - return 1; - - return 0; -} - -static inline enum ntb_topo atom_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) -{ - struct device *dev = &ndev->ntb.pdev->dev; - - switch (ppd & ATOM_PPD_TOPO_MASK) { - case ATOM_PPD_TOPO_B2B_USD: - dev_dbg(dev, "PPD %d B2B USD\n", ppd); - return NTB_TOPO_B2B_USD; - - case ATOM_PPD_TOPO_B2B_DSD: - dev_dbg(dev, "PPD %d B2B DSD\n", ppd); - return NTB_TOPO_B2B_DSD; - - case ATOM_PPD_TOPO_PRI_USD: - case ATOM_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ - case ATOM_PPD_TOPO_SEC_USD: - case ATOM_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ - dev_dbg(dev, "PPD %d non B2B disabled\n", ppd); - return NTB_TOPO_NONE; - } - - dev_dbg(dev, "PPD %d invalid\n", ppd); - return NTB_TOPO_NONE; -} - -static void atom_link_hb(struct work_struct *work) -{ - struct intel_ntb_dev *ndev = hb_ndev(work); - struct device *dev = &ndev->ntb.pdev->dev; - unsigned long poll_ts; - void __iomem *mmio; - u32 status32; - - poll_ts = ndev->last_ts + ATOM_LINK_HB_TIMEOUT; - - /* Delay polling the link status if an interrupt was received, - * unless the cached link status says the link is down. - */ - if (time_after(poll_ts, jiffies) && atom_link_is_up(ndev)) { - schedule_delayed_work(&ndev->hb_timer, poll_ts - jiffies); - return; - } - - if (atom_poll_link(ndev)) - ntb_link_event(&ndev->ntb); - - if (atom_link_is_up(ndev) || !atom_link_is_err(ndev)) { - schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_HB_TIMEOUT); - return; - } - - /* Link is down with error: recover the link! */ - - mmio = ndev->self_mmio; - - /* Driver resets the NTB ModPhy lanes - magic! */ - iowrite8(0xe0, mmio + ATOM_MODPHY_PCSREG6); - iowrite8(0x40, mmio + ATOM_MODPHY_PCSREG4); - iowrite8(0x60, mmio + ATOM_MODPHY_PCSREG4); - iowrite8(0x60, mmio + ATOM_MODPHY_PCSREG6); - - /* Driver waits 100ms to allow the NTB ModPhy to settle */ - msleep(100); - - /* Clear AER Errors, write to clear */ - status32 = ioread32(mmio + ATOM_ERRCORSTS_OFFSET); - dev_dbg(dev, "ERRCORSTS = %x\n", status32); - status32 &= PCI_ERR_COR_REP_ROLL; - iowrite32(status32, mmio + ATOM_ERRCORSTS_OFFSET); - - /* Clear unexpected electrical idle event in LTSSM, write to clear */ - status32 = ioread32(mmio + ATOM_LTSSMERRSTS0_OFFSET); - dev_dbg(dev, "LTSSMERRSTS0 = %x\n", status32); - status32 |= ATOM_LTSSMERRSTS0_UNEXPECTEDEI; - iowrite32(status32, mmio + ATOM_LTSSMERRSTS0_OFFSET); - - /* Clear DeSkew Buffer error, write to clear */ - status32 = ioread32(mmio + ATOM_DESKEWSTS_OFFSET); - dev_dbg(dev, "DESKEWSTS = %x\n", status32); - status32 |= ATOM_DESKEWSTS_DBERR; - iowrite32(status32, mmio + ATOM_DESKEWSTS_OFFSET); - - status32 = ioread32(mmio + ATOM_IBSTERRRCRVSTS0_OFFSET); - dev_dbg(dev, "IBSTERRRCRVSTS0 = %x\n", status32); - status32 &= ATOM_IBIST_ERR_OFLOW; - iowrite32(status32, mmio + ATOM_IBSTERRRCRVSTS0_OFFSET); - - /* Releases the NTB state machine to allow the link to retrain */ - status32 = ioread32(mmio + ATOM_LTSSMSTATEJMP_OFFSET); - dev_dbg(dev, "LTSSMSTATEJMP = %x\n", status32); - status32 &= ~ATOM_LTSSMSTATEJMP_FORCEDETECT; - iowrite32(status32, mmio + ATOM_LTSSMSTATEJMP_OFFSET); - - /* There is a potential race between the 2 NTB devices recovering at the - * same time. If the times are the same, the link will not recover and - * the driver will be stuck in this loop forever. Add a random interval - * to the recovery time to prevent this race. - */ - schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_RECOVERY_TIME - + prandom_u32() % ATOM_LINK_RECOVERY_TIME); -} - -static int atom_init_isr(struct intel_ntb_dev *ndev) -{ - int rc; - - rc = ndev_init_isr(ndev, 1, ATOM_DB_MSIX_VECTOR_COUNT, - ATOM_DB_MSIX_VECTOR_SHIFT, ATOM_DB_TOTAL_SHIFT); - if (rc) - return rc; - - /* ATOM doesn't have link status interrupt, poll on that platform */ - ndev->last_ts = jiffies; - INIT_DELAYED_WORK(&ndev->hb_timer, atom_link_hb); - schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_HB_TIMEOUT); - - return 0; -} - -static void atom_deinit_isr(struct intel_ntb_dev *ndev) -{ - cancel_delayed_work_sync(&ndev->hb_timer); - ndev_deinit_isr(ndev); -} - -static int atom_init_ntb(struct intel_ntb_dev *ndev) -{ - ndev->mw_count = ATOM_MW_COUNT; - ndev->spad_count = ATOM_SPAD_COUNT; - ndev->db_count = ATOM_DB_COUNT; - - switch (ndev->ntb.topo) { - case NTB_TOPO_B2B_USD: - case NTB_TOPO_B2B_DSD: - ndev->self_reg = &atom_pri_reg; - ndev->peer_reg = &atom_b2b_reg; - ndev->xlat_reg = &atom_sec_xlat; - - /* Enable Bus Master and Memory Space on the secondary side */ - iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->self_mmio + ATOM_SPCICMD_OFFSET); - - break; - - default: - return -EINVAL; - } - - ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; - - return 0; -} - -static int atom_init_dev(struct intel_ntb_dev *ndev) -{ - u32 ppd; - int rc; - - rc = pci_read_config_dword(ndev->ntb.pdev, ATOM_PPD_OFFSET, &ppd); - if (rc) - return -EIO; - - ndev->ntb.topo = atom_ppd_topo(ndev, ppd); - if (ndev->ntb.topo == NTB_TOPO_NONE) - return -EINVAL; - - rc = atom_init_ntb(ndev); - if (rc) - return rc; - - rc = atom_init_isr(ndev); - if (rc) - return rc; - - if (ndev->ntb.topo != NTB_TOPO_SEC) { - /* Initiate PCI-E link training */ - rc = pci_write_config_dword(ndev->ntb.pdev, ATOM_PPD_OFFSET, - ppd | ATOM_PPD_INIT_LINK); - if (rc) - return rc; - } - - return 0; -} - -static void atom_deinit_dev(struct intel_ntb_dev *ndev) -{ - atom_deinit_isr(ndev); -} - /* Skylake Xeon NTB */ static int skx_poll_link(struct intel_ntb_dev *ndev) @@ -2658,24 +2406,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, node = dev_to_node(&pdev->dev); - if (pdev_is_atom(pdev)) { - ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); - if (!ndev) { - rc = -ENOMEM; - goto err_ndev; - } - - ndev_init_struct(ndev, pdev); - - rc = intel_ntb_init_pci(ndev, pdev); - if (rc) - goto err_init_pci; - - rc = atom_init_dev(ndev); - if (rc) - goto err_init_dev; - - } else if (pdev_is_xeon(pdev)) { + if (pdev_is_xeon(pdev)) { ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; @@ -2731,9 +2462,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, err_register: ndev_deinit_debugfs(ndev); - if (pdev_is_atom(pdev)) - atom_deinit_dev(ndev); - else if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) + if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) xeon_deinit_dev(ndev); err_init_dev: intel_ntb_deinit_pci(ndev); @@ -2749,41 +2478,12 @@ static void intel_ntb_pci_remove(struct pci_dev *pdev) ntb_unregister_device(&ndev->ntb); ndev_deinit_debugfs(ndev); - if (pdev_is_atom(pdev)) - atom_deinit_dev(ndev); - else if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) + if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) xeon_deinit_dev(ndev); intel_ntb_deinit_pci(ndev); kfree(ndev); } -static const struct intel_ntb_reg atom_reg = { - .poll_link = atom_poll_link, - .link_is_up = atom_link_is_up, - .db_ioread = atom_db_ioread, - .db_iowrite = atom_db_iowrite, - .db_size = sizeof(u64), - .ntb_ctl = ATOM_NTBCNTL_OFFSET, - .mw_bar = {2, 4}, -}; - -static const struct intel_ntb_alt_reg atom_pri_reg = { - .db_bell = ATOM_PDOORBELL_OFFSET, - .db_mask = ATOM_PDBMSK_OFFSET, - .spad = ATOM_SPAD_OFFSET, -}; - -static const struct intel_ntb_alt_reg atom_b2b_reg = { - .db_bell = ATOM_B2B_DOORBELL_OFFSET, - .spad = ATOM_B2B_SPAD_OFFSET, -}; - -static const struct intel_ntb_xlat_reg atom_sec_xlat = { - /* FIXME : .bar0_base = ATOM_SBAR0BASE_OFFSET, */ - /* FIXME : .bar2_limit = ATOM_SBAR2LMT_OFFSET, */ - .bar2_xlat = ATOM_SBAR2XLAT_OFFSET, -}; - static const struct intel_ntb_reg xeon_reg = { .poll_link = xeon_poll_link, .link_is_up = xeon_link_is_up, @@ -2940,7 +2640,6 @@ static const struct file_operations intel_ntb_debugfs_info = { }; static const struct pci_device_id intel_ntb_pci_tbl[] = { - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 2d6c38afb128..4415aa7ea775 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -66,7 +66,6 @@ #define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D #define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E #define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E #define PCI_DEVICE_ID_INTEL_NTB_B2B_BDX 0x6F0D #define PCI_DEVICE_ID_INTEL_NTB_PS_BDX 0x6F0E #define PCI_DEVICE_ID_INTEL_NTB_SS_BDX 0x6F0F @@ -196,63 +195,6 @@ #define SKX_DB_TOTAL_SHIFT 33 #define SKX_SPAD_COUNT 16 -/* Intel Atom hardware */ - -#define ATOM_SBAR2XLAT_OFFSET 0x0008 -#define ATOM_PDOORBELL_OFFSET 0x0020 -#define ATOM_PDBMSK_OFFSET 0x0028 -#define ATOM_NTBCNTL_OFFSET 0x0060 -#define ATOM_SPAD_OFFSET 0x0080 -#define ATOM_PPD_OFFSET 0x00d4 -#define ATOM_PBAR2XLAT_OFFSET 0x8008 -#define ATOM_B2B_DOORBELL_OFFSET 0x8020 -#define ATOM_B2B_SPAD_OFFSET 0x8080 -#define ATOM_SPCICMD_OFFSET 0xb004 -#define ATOM_LINK_STATUS_OFFSET 0xb052 -#define ATOM_ERRCORSTS_OFFSET 0xb110 -#define ATOM_IP_BASE 0xc000 -#define ATOM_DESKEWSTS_OFFSET (ATOM_IP_BASE + 0x3024) -#define ATOM_LTSSMERRSTS0_OFFSET (ATOM_IP_BASE + 0x3180) -#define ATOM_LTSSMSTATEJMP_OFFSET (ATOM_IP_BASE + 0x3040) -#define ATOM_IBSTERRRCRVSTS0_OFFSET (ATOM_IP_BASE + 0x3324) -#define ATOM_MODPHY_PCSREG4 0x1c004 -#define ATOM_MODPHY_PCSREG6 0x1c006 - -#define ATOM_PPD_INIT_LINK 0x0008 -#define ATOM_PPD_CONN_MASK 0x0300 -#define ATOM_PPD_CONN_TRANSPARENT 0x0000 -#define ATOM_PPD_CONN_B2B 0x0100 -#define ATOM_PPD_CONN_RP 0x0200 -#define ATOM_PPD_DEV_MASK 0x1000 -#define ATOM_PPD_DEV_USD 0x0000 -#define ATOM_PPD_DEV_DSD 0x1000 -#define ATOM_PPD_TOPO_MASK (ATOM_PPD_CONN_MASK | ATOM_PPD_DEV_MASK) -#define ATOM_PPD_TOPO_PRI_USD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_USD) -#define ATOM_PPD_TOPO_PRI_DSD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_DSD) -#define ATOM_PPD_TOPO_SEC_USD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_USD) -#define ATOM_PPD_TOPO_SEC_DSD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_DSD) -#define ATOM_PPD_TOPO_B2B_USD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_USD) -#define ATOM_PPD_TOPO_B2B_DSD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_DSD) - -#define ATOM_MW_COUNT 2 -#define ATOM_DB_COUNT 34 -#define ATOM_DB_VALID_MASK (BIT_ULL(ATOM_DB_COUNT) - 1) -#define ATOM_DB_MSIX_VECTOR_COUNT 34 -#define ATOM_DB_MSIX_VECTOR_SHIFT 1 -#define ATOM_DB_TOTAL_SHIFT 34 -#define ATOM_SPAD_COUNT 16 - -#define ATOM_NTB_CTL_DOWN_BIT BIT(16) -#define ATOM_NTB_CTL_ACTIVE(x) !(x & ATOM_NTB_CTL_DOWN_BIT) - -#define ATOM_DESKEWSTS_DBERR BIT(15) -#define ATOM_LTSSMERRSTS0_UNEXPECTEDEI BIT(20) -#define ATOM_LTSSMSTATEJMP_FORCEDETECT BIT(2) -#define ATOM_IBIST_ERR_OFLOW 0x7FFF7FFF - -#define ATOM_LINK_HB_TIMEOUT msecs_to_jiffies(1000) -#define ATOM_LINK_RECOVERY_TIME msecs_to_jiffies(500) - /* Ntb control and link status */ #define NTB_CTL_CFG_LOCK BIT(0) -- cgit From c5ec8b451a02674882c75f51073a4f0323b37550 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 21 Nov 2017 22:59:45 +0000 Subject: NTB: switchtec_ntb: fix spelling mistake: "peforming" -> "performing" Trivial fix to spelling mistake in dev_err error message Signed-off-by: Colin Ian King Reviewed-By: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index ca0334a6b759..c23b4e3f280f 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -172,7 +172,7 @@ static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, if (ps == status) { dev_err(&sndev->stdev->dev, - "Timed out while peforming %s (%d). (%08x)", + "Timed out while performing %s (%d). (%08x)", op_text[op], op, ioread32(&ctl->partition_status)); -- cgit From 2dd0f6a64a36bf7176c6055c919da3f53b7924f3 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Mon, 27 Nov 2017 11:03:57 -0500 Subject: NTB: switchtec_ntb: Add new line on appropriate printks Trivial addition of "\n" to the dev_* prints where necessary Signed-off-by: Joe Perches Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index c23b4e3f280f..709f37fbe232 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -172,7 +172,7 @@ static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, if (ps == status) { dev_err(&sndev->stdev->dev, - "Timed out while performing %s (%d). (%08x)", + "Timed out while performing %s (%d). (%08x)\n", op_text[op], op, ioread32(&ctl->partition_status)); @@ -306,7 +306,7 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, if (pidx != NTB_DEF_PEER_IDX) return -EINVAL; - dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap", + dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap\n", widx, pidx, &addr, &size); if (widx >= switchtec_ntb_mw_count(ntb, pidx)) @@ -337,7 +337,7 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, if (rc == -EIO) { dev_err(&sndev->stdev->dev, - "Hardware reported an error configuring mw %d: %08x", + "Hardware reported an error configuring mw %d: %08x\n", widx, ioread32(&ctl->bar_error)); if (widx < nr_direct_mw) @@ -491,7 +491,7 @@ static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) if (link_sta != old) { switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK); ntb_link_event(&sndev->ntb); - dev_info(&sndev->stdev->dev, "ntb link %s", + dev_info(&sndev->stdev->dev, "ntb link %s\n", link_sta ? "up" : "down"); } } @@ -523,7 +523,7 @@ static int switchtec_ntb_link_enable(struct ntb_dev *ntb, { struct switchtec_ntb *sndev = ntb_sndev(ntb); - dev_dbg(&sndev->stdev->dev, "enabling link"); + dev_dbg(&sndev->stdev->dev, "enabling link\n"); sndev->self_shared->link_sta = 1; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); @@ -537,7 +537,7 @@ static int switchtec_ntb_link_disable(struct ntb_dev *ntb) { struct switchtec_ntb *sndev = ntb_sndev(ntb); - dev_dbg(&sndev->stdev->dev, "disabling link"); + dev_dbg(&sndev->stdev->dev, "disabling link\n"); sndev->self_shared->link_sta = 0; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); @@ -792,7 +792,7 @@ static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) part_map &= ~(1 << sndev->self_partition); sndev->peer_partition = ffs(part_map) - 1; - dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)", + dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)\n", sndev->self_partition, sndev->stdev->partition_count, part_map); @@ -829,7 +829,7 @@ static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries); sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); - dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut", + dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut\n", sndev->nr_direct_mw, sndev->nr_lut_mw); sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar, @@ -839,7 +839,7 @@ static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) ioread16(&sndev->mmio_peer_ctrl->lut_table_entries); sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); - dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut", + dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut\n", sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw); } @@ -897,7 +897,7 @@ static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) { dev_err(&sndev->stdev->dev, - "Not enough requester IDs available."); + "Not enough requester IDs available\n"); return -EFAULT; } @@ -928,7 +928,7 @@ static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) if (rc == -EIO) { error = ioread32(&sndev->mmio_self_ctrl->req_id_error); dev_err(&sndev->stdev->dev, - "Error setting up the requester ID table: %08x", + "Error setting up the requester ID table: %08x\n", error); } @@ -975,7 +975,7 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) GFP_KERNEL); if (!sndev->self_shared) { dev_err(&sndev->stdev->dev, - "unable to allocate memory for shared mw"); + "unable to allocate memory for shared mw\n"); return -ENOMEM; } @@ -1005,7 +1005,7 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) bar_error = ioread32(&ctl->bar_error); lut_error = ioread32(&ctl->lut_error); dev_err(&sndev->stdev->dev, - "Error setting up shared MW: %08x / %08x", + "Error setting up shared MW: %08x / %08x\n", bar_error, lut_error); goto unalloc_and_exit; } @@ -1016,7 +1016,7 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) goto unalloc_and_exit; } - dev_dbg(&sndev->stdev->dev, "Shared MW Ready"); + dev_dbg(&sndev->stdev->dev, "Shared MW Ready\n"); return 0; unalloc_and_exit: @@ -1057,8 +1057,8 @@ static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev) u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]); if (msg & NTB_DBMSG_IMSG_STATUS) { - dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i, - (u32)msg); + dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", + i, (u32)msg); iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); if (i == LINK_MESSAGE) @@ -1086,7 +1086,7 @@ static int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev) message_irq == event_irq) message_irq++; - dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d", + dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d\n", event_irq, doorbell_irq, message_irq); for (i = 0; i < idb_vecs - 4; i++) @@ -1136,7 +1136,7 @@ static int switchtec_ntb_add(struct device *dev, return -ENODEV; if (stdev->partition_count != 2) - dev_warn(dev, "ntb driver only supports 2 partitions"); + dev_warn(dev, "ntb driver only supports 2 partitions\n"); sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); if (!sndev) @@ -1166,7 +1166,7 @@ static int switchtec_ntb_add(struct device *dev, stdev->sndev = sndev; stdev->link_notifier = switchtec_ntb_link_notification; - dev_info(dev, "NTB device registered"); + dev_info(dev, "NTB device registered\n"); return 0; @@ -1176,7 +1176,7 @@ deinit_shared_and_exit: switchtec_ntb_deinit_shared_mw(sndev); free_and_exit: kfree(sndev); - dev_err(dev, "failed to register ntb device: %d", rc); + dev_err(dev, "failed to register ntb device: %d\n", rc); return rc; } @@ -1195,7 +1195,7 @@ void switchtec_ntb_remove(struct device *dev, switchtec_ntb_deinit_db_msg_irq(sndev); switchtec_ntb_deinit_shared_mw(sndev); kfree(sndev); - dev_info(dev, "ntb device unregistered"); + dev_info(dev, "ntb device unregistered\n"); } static struct class_interface switchtec_interface = { -- cgit From 3df54c870f52b4c47b53eead8d22a109f741b91c Mon Sep 17 00:00:00 2001 From: Kelvin Cao Date: Wed, 29 Nov 2017 10:55:24 -0700 Subject: ntb_hw_switchtec: Allow using Switchtec NTB in multi-partition setups Allow using Switchtec NTB in setups that have more than two partitions. Note: this does not enable having multi-host communication, it only allows for a single NTB link between two hosts in a network that might have more than two. Use following logic to determine the NT peer partition: 1) If there are 2 partitions, and the target vector is set in the Switchtec configuration, use the partition specified in target vector. 2) If there are 2 partitions and target vector is unset use the only other partition as specified in the NT EP map. 3) If there are more than 2 partitions and target vector is set use the other partition specified in target vector. 4) If there are more than 2 partitions and target vector is unset, this is invalid and report an error. Signed-off-by: Kelvin Cao [logang@deltatee.com: commit message fleshed out] Signed-off-by: Logan Gunthorpe Reviewed-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 57 ++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 709f37fbe232..088ae220ecb4 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -777,9 +777,12 @@ static const struct ntb_dev_ops switchtec_ntb_ops = { .peer_spad_addr = switchtec_ntb_peer_spad_addr, }; -static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) +static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) { + u64 tpart_vec; + int self; u64 part_map; + int bit; sndev->ntb.pdev = sndev->stdev->pdev; sndev->ntb.topo = NTB_TOPO_SWITCH; @@ -788,13 +791,47 @@ static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) sndev->self_partition = sndev->stdev->partition; sndev->mmio_ntb = sndev->stdev->mmio_ntb; + + self = sndev->self_partition; + tpart_vec = ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_high); + tpart_vec <<= 32; + tpart_vec |= ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_low); + part_map = ioread64(&sndev->mmio_ntb->ep_map); part_map &= ~(1 << sndev->self_partition); - sndev->peer_partition = ffs(part_map) - 1; - dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)\n", - sndev->self_partition, sndev->stdev->partition_count, - part_map); + if (!ffs(tpart_vec)) { + if (sndev->stdev->partition_count != 2) { + dev_err(&sndev->stdev->dev, + "ntb target partition not defined\n"); + return -ENODEV; + } + + bit = ffs(part_map); + if (!bit) { + dev_err(&sndev->stdev->dev, + "peer partition is not NT partition\n"); + return -ENODEV; + } + + sndev->peer_partition = bit - 1; + } else { + if (ffs(tpart_vec) != fls(tpart_vec)) { + dev_err(&sndev->stdev->dev, + "ntb driver only supports 1 pair of 1-1 ntb mapping\n"); + return -ENODEV; + } + + sndev->peer_partition = ffs(tpart_vec) - 1; + if (!(part_map && (1 << sndev->peer_partition))) { + dev_err(&sndev->stdev->dev, + "ntb target partition is not NT partition\n"); + return -ENODEV; + } + } + + dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d\n", + sndev->self_partition, sndev->stdev->partition_count); sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb + SWITCHTEC_NTB_REG_CTRL_OFFSET; @@ -804,6 +841,8 @@ static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; + + return 0; } static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) @@ -1135,15 +1174,15 @@ static int switchtec_ntb_add(struct device *dev, if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE) return -ENODEV; - if (stdev->partition_count != 2) - dev_warn(dev, "ntb driver only supports 2 partitions\n"); - sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); if (!sndev) return -ENOMEM; sndev->stdev = stdev; - switchtec_ntb_init_sndev(sndev); + rc = switchtec_ntb_init_sndev(sndev); + if (rc) + goto free_and_exit; + switchtec_ntb_init_mw(sndev); switchtec_ntb_init_db(sndev); switchtec_ntb_init_msgs(sndev); -- cgit From c3585cd8708edb1c16fa84f8f3dee31741a66a9e Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Wed, 29 Nov 2017 10:55:25 -0700 Subject: ntb_hw_switchtec: Keep track of the number of LUT windows used by the driver This is a prep patch in order to support the crosslink feature which will require the driver to use another reserved LUT window. To simplify this, we add some code to track the number of reserved LUT windows in use instead of assuming this is always 1. Signed-off-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 088ae220ecb4..51fec6497164 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -109,6 +109,7 @@ struct switchtec_ntb { int nr_direct_mw; int nr_lut_mw; + int nr_rsvd_luts; int direct_mw_to_bar[MAX_DIRECT_MW]; int peer_nr_direct_mw; @@ -197,7 +198,7 @@ static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) { struct switchtec_ntb *sndev = ntb_sndev(ntb); int nr_direct_mw = sndev->peer_nr_direct_mw; - int nr_lut_mw = sndev->peer_nr_lut_mw - 1; + int nr_lut_mw = sndev->peer_nr_lut_mw - sndev->nr_rsvd_luts; if (pidx != NTB_DEF_PEER_IDX) return -EINVAL; @@ -210,12 +211,12 @@ static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) static int lut_index(struct switchtec_ntb *sndev, int mw_idx) { - return mw_idx - sndev->nr_direct_mw + 1; + return mw_idx - sndev->nr_direct_mw + sndev->nr_rsvd_luts; } static int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx) { - return mw_idx - sndev->peer_nr_direct_mw + 1; + return mw_idx - sndev->peer_nr_direct_mw + sndev->nr_rsvd_luts; } static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, @@ -355,8 +356,9 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) { struct switchtec_ntb *sndev = ntb_sndev(ntb); + int nr_lut_mw = sndev->nr_lut_mw - sndev->nr_rsvd_luts; - return sndev->nr_direct_mw + (use_lut_mws ? sndev->nr_lut_mw - 1 : 0); + return sndev->nr_direct_mw + (use_lut_mws ? nr_lut_mw : 0); } static int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev, @@ -1008,6 +1010,7 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) u32 ctl_val; int rc; + sndev->nr_rsvd_luts++; sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, &sndev->self_shared_dma, @@ -1074,6 +1077,7 @@ static void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev) dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, sndev->self_shared, sndev->self_shared_dma); + sndev->nr_rsvd_luts--; } static irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev) -- cgit From 12cb203b1b3e2a43d6e3f5f5c6e2071636334fc2 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Wed, 29 Nov 2017 10:55:26 -0700 Subject: ntb_hw_switchtec: Create helper function to setup reserved LUT MWs This is a prep patch in order to support the crosslink feature which will require the driver to use another reserved LUT window. To simplify this we move the code which sets up the reserved LUT window into a helper function which will be used by the crosslink initialization. Signed-off-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 72 ++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 51fec6497164..b18e938312e1 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -847,6 +847,46 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) return 0; } +static int config_rsvd_lut_win(struct switchtec_ntb *sndev, + struct ntb_ctrl_regs __iomem *ctl, + int lut_idx, int partition, + dma_addr_t addr) +{ + int peer_bar = sndev->peer_direct_mw_to_bar[0]; + u32 ctl_val; + int rc; + + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, + NTB_CTRL_PART_STATUS_LOCKED); + if (rc) + return rc; + + ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl); + ctl_val &= 0xFF; + ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; + ctl_val |= ilog2(LUT_SIZE) << 8; + ctl_val |= (sndev->nr_lut_mw - 1) << 14; + iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl); + + iowrite64((NTB_CTRL_LUT_EN | (partition << 1) | addr), + &ctl->lut_entry[lut_idx]); + + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, + NTB_CTRL_PART_STATUS_NORMAL); + if (rc) { + u32 bar_error, lut_error; + + bar_error = ioread32(&ctl->bar_error); + lut_error = ioread32(&ctl->lut_error); + dev_err(&sndev->stdev->dev, + "Error setting up reserved lut window: %08x / %08x\n", + bar_error, lut_error); + return rc; + } + + return 0; +} + static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) { int i; @@ -1004,10 +1044,7 @@ static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) { - struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; int self_bar = sndev->direct_mw_to_bar[0]; - int peer_bar = sndev->peer_direct_mw_to_bar[0]; - u32 ctl_val; int rc; sndev->nr_rsvd_luts++; @@ -1023,35 +1060,12 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) switchtec_ntb_init_shared(sndev); - rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, - NTB_CTRL_PART_STATUS_LOCKED); + rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, + sndev->self_partition, + sndev->self_shared_dma); if (rc) goto unalloc_and_exit; - ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl); - ctl_val &= 0xFF; - ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; - ctl_val |= ilog2(LUT_SIZE) << 8; - ctl_val |= (sndev->nr_lut_mw - 1) << 14; - iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl); - - iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | - sndev->self_shared_dma), - &ctl->lut_entry[0]); - - rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, - NTB_CTRL_PART_STATUS_NORMAL); - if (rc) { - u32 bar_error, lut_error; - - bar_error = ioread32(&ctl->bar_error); - lut_error = ioread32(&ctl->lut_error); - dev_err(&sndev->stdev->dev, - "Error setting up shared MW: %08x / %08x\n", - bar_error, lut_error); - goto unalloc_and_exit; - } - sndev->peer_shared = pci_iomap(sndev->stdev->pdev, self_bar, LUT_SIZE); if (!sndev->peer_shared) { rc = -ENOMEM; -- cgit From bbe35ca5aa2b9e7413c3b14c4887e05829bcd822 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Wed, 29 Nov 2017 10:55:27 -0700 Subject: ntb_hw_switchtec: Make switchtec_ntb_init_req_id_table() more general This is a prep patch in order to support the crosslink feature which will require the driver to setup the requester ID table in another partition as well as it's own. To aid this, create a helper function which sets up the requester IDs from an array. Signed-off-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 92 +++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index b18e938312e1..4adc32fe035a 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -887,6 +887,55 @@ static int config_rsvd_lut_win(struct switchtec_ntb *sndev, return 0; } +static int config_req_id_table(struct switchtec_ntb *sndev, + struct ntb_ctrl_regs __iomem *mmio_ctrl, + int *req_ids, int count) +{ + int i, rc = 0; + u32 error; + u32 proxy_id; + + if (ioread32(&mmio_ctrl->req_id_table_size) < count) { + dev_err(&sndev->stdev->dev, + "Not enough requester IDs available.\n"); + return -EFAULT; + } + + rc = switchtec_ntb_part_op(sndev, mmio_ctrl, + NTB_CTRL_PART_OP_LOCK, + NTB_CTRL_PART_STATUS_LOCKED); + if (rc) + return rc; + + iowrite32(NTB_PART_CTRL_ID_PROT_DIS, + &mmio_ctrl->partition_ctrl); + + for (i = 0; i < count; i++) { + iowrite32(req_ids[i] << 16 | NTB_CTRL_REQ_ID_EN, + &mmio_ctrl->req_id_table[i]); + + proxy_id = ioread32(&mmio_ctrl->req_id_table[i]); + dev_dbg(&sndev->stdev->dev, + "Requester ID %02X:%02X.%X -> BB:%02X.%X\n", + req_ids[i] >> 8, (req_ids[i] >> 3) & 0x1F, + req_ids[i] & 0x7, (proxy_id >> 4) & 0x1F, + (proxy_id >> 1) & 0x7); + } + + rc = switchtec_ntb_part_op(sndev, mmio_ctrl, + NTB_CTRL_PART_OP_CFG, + NTB_CTRL_PART_STATUS_NORMAL); + + if (rc == -EIO) { + error = ioread32(&mmio_ctrl->req_id_error); + dev_err(&sndev->stdev->dev, + "Error setting up the requester ID table: %08x\n", + error); + } + + return 0; +} + static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) { int i; @@ -968,52 +1017,23 @@ static void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev) &sndev->mmio_self_dbmsg->imsg[i]); } -static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) +static int +switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) { - int rc = 0; - u16 req_id; - u32 error; - - req_id = ioread16(&sndev->mmio_ntb->requester_id); - - if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) { - dev_err(&sndev->stdev->dev, - "Not enough requester IDs available\n"); - return -EFAULT; - } - - rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, - NTB_CTRL_PART_OP_LOCK, - NTB_CTRL_PART_STATUS_LOCKED); - if (rc) - return rc; - - iowrite32(NTB_PART_CTRL_ID_PROT_DIS, - &sndev->mmio_self_ctrl->partition_ctrl); + int req_ids[2]; /* * Root Complex Requester ID (which is 0:00.0) */ - iowrite32(0 << 16 | NTB_CTRL_REQ_ID_EN, - &sndev->mmio_self_ctrl->req_id_table[0]); + req_ids[0] = 0; /* * Host Bridge Requester ID (as read from the mmap address) */ - iowrite32(req_id << 16 | NTB_CTRL_REQ_ID_EN, - &sndev->mmio_self_ctrl->req_id_table[1]); - - rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, - NTB_CTRL_PART_OP_CFG, - NTB_CTRL_PART_STATUS_NORMAL); - if (rc == -EIO) { - error = ioread32(&sndev->mmio_self_ctrl->req_id_error); - dev_err(&sndev->stdev->dev, - "Error setting up the requester ID table: %08x\n", - error); - } + req_ids[1] = ioread16(&sndev->mmio_ntb->requester_id); - return rc; + return config_req_id_table(sndev, sndev->mmio_self_ctrl, req_ids, + ARRAY_SIZE(req_ids)); } static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) -- cgit From 01752501820277d217a7b52548d9c948f98d2c56 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Wed, 29 Nov 2017 10:55:29 -0700 Subject: ntb_hw_switchtec: Add initialization code for crosslink Crosslink is a feature of the Switchtec switches that is similar to the B2B mode of other NTB devices. It allows a system to be designed that is perfectly symmetric with two identical switches that link two hosts together. In order for the system to be symmetric, there is an empty host-less partition between the two switches which the host must enumerate and assign BAR addresses to. The firmware in the switch manages this specially so that the BAR addresses on both sides of the empty partition will be identical despite being in the same partition with the same address space. The driver determines whether crosslink is enabled by a flag set in the NTB partition info registers which are set by the switch's configuration file. When crosslink is enabled, a reserved LUT window is setup to point to the peer's switch's NTB registers and the local MWs are set to forward to the host-less partition's BARs. (Yes, this hurts my brain too.) Once this is setup, largely the same NTB infrastructure is used to communicate between the two hosts. Signed-off-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 202 ++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 4adc32fe035a..17db0f50bb22 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -95,6 +95,8 @@ struct switchtec_ntb { struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; + void __iomem *mmio_xlink_win; + struct shared_mw *self_shared; struct shared_mw __iomem *peer_shared; dma_addr_t self_shared_dma; @@ -465,6 +467,13 @@ static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev) sndev->link_width = min(self_width, peer_width); } +static int crosslink_is_enabled(struct switchtec_ntb *sndev) +{ + struct ntb_info_regs __iomem *inf = sndev->mmio_ntb; + + return ioread8(&inf->ntp_info[sndev->peer_partition].xlink_enabled); +} + enum { LINK_MESSAGE = 0, MSG_LINK_UP = 1, @@ -849,8 +858,7 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) static int config_rsvd_lut_win(struct switchtec_ntb *sndev, struct ntb_ctrl_regs __iomem *ctl, - int lut_idx, int partition, - dma_addr_t addr) + int lut_idx, int partition, u64 addr) { int peer_bar = sndev->peer_direct_mw_to_bar[0]; u32 ctl_val; @@ -936,6 +944,182 @@ static int config_req_id_table(struct switchtec_ntb *sndev, return 0; } +static int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx, + u64 *mw_addrs, int mw_count) +{ + int rc, i; + struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_self_ctrl; + u64 addr; + size_t size, offset; + int bar; + int xlate_pos; + u32 ctl_val; + + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, + NTB_CTRL_PART_STATUS_LOCKED); + if (rc) + return rc; + + for (i = 0; i < sndev->nr_lut_mw; i++) { + if (i == ntb_lut_idx) + continue; + + addr = mw_addrs[0] + LUT_SIZE * i; + + iowrite64((NTB_CTRL_LUT_EN | (sndev->peer_partition << 1) | + addr), + &ctl->lut_entry[i]); + } + + sndev->nr_direct_mw = min_t(int, sndev->nr_direct_mw, mw_count); + + for (i = 0; i < sndev->nr_direct_mw; i++) { + bar = sndev->direct_mw_to_bar[i]; + offset = (i == 0) ? LUT_SIZE * sndev->nr_lut_mw : 0; + addr = mw_addrs[i] + offset; + size = pci_resource_len(sndev->ntb.pdev, bar) - offset; + xlate_pos = ilog2(size); + + if (offset && size > offset) + size = offset; + + ctl_val = ioread32(&ctl->bar_entry[bar].ctl); + ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; + + iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); + iowrite32(xlate_pos | size, &ctl->bar_entry[bar].win_size); + iowrite64(sndev->peer_partition | addr, + &ctl->bar_entry[bar].xlate_addr); + } + + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, + NTB_CTRL_PART_STATUS_NORMAL); + if (rc) { + u32 bar_error, lut_error; + + bar_error = ioread32(&ctl->bar_error); + lut_error = ioread32(&ctl->lut_error); + dev_err(&sndev->stdev->dev, + "Error setting up cross link windows: %08x / %08x\n", + bar_error, lut_error); + return rc; + } + + return 0; +} + +static int crosslink_setup_req_ids(struct switchtec_ntb *sndev, + struct ntb_ctrl_regs __iomem *mmio_ctrl) +{ + int req_ids[16]; + int i; + u32 proxy_id; + + for (i = 0; i < ARRAY_SIZE(req_ids); i++) { + proxy_id = ioread32(&sndev->mmio_self_ctrl->req_id_table[i]); + + if (!(proxy_id & NTB_CTRL_REQ_ID_EN)) + break; + + req_ids[i] = ((proxy_id >> 1) & 0xFF); + } + + return config_req_id_table(sndev, mmio_ctrl, req_ids, i); +} + +/* + * In crosslink configuration there is a virtual partition in the + * middle of the two switches. The BARs in this partition have to be + * enumerated and assigned addresses. + */ +static int crosslink_enum_partition(struct switchtec_ntb *sndev, + u64 *bar_addrs) +{ + struct part_cfg_regs __iomem *part_cfg = + &sndev->stdev->mmio_part_cfg_all[sndev->peer_partition]; + u32 pff = ioread32(&part_cfg->vep_pff_inst_id); + struct pff_csr_regs __iomem *mmio_pff = + &sndev->stdev->mmio_pff_csr[pff]; + const u64 bar_space = 0x1000000000LL; + u64 bar_addr; + int bar_cnt = 0; + int i; + + iowrite16(0x6, &mmio_pff->pcicmd); + + for (i = 0; i < ARRAY_SIZE(mmio_pff->pci_bar64); i++) { + iowrite64(bar_space * i, &mmio_pff->pci_bar64[i]); + bar_addr = ioread64(&mmio_pff->pci_bar64[i]); + bar_addr &= ~0xf; + + dev_dbg(&sndev->stdev->dev, + "Crosslink BAR%d addr: %llx\n", + i, bar_addr); + + if (bar_addr != bar_space * i) + continue; + + bar_addrs[bar_cnt++] = bar_addr; + } + + return bar_cnt; +} + +static int switchtec_ntb_init_crosslink(struct switchtec_ntb *sndev) +{ + int rc; + int bar = sndev->direct_mw_to_bar[0]; + const int ntb_lut_idx = 1; + u64 bar_addrs[6]; + u64 addr; + int bar_cnt; + + if (!crosslink_is_enabled(sndev)) + return 0; + + dev_info(&sndev->stdev->dev, "Using crosslink configuration\n"); + sndev->ntb.topo = NTB_TOPO_CROSSLINK; + + bar_cnt = crosslink_enum_partition(sndev, bar_addrs); + if (bar_cnt < sndev->nr_direct_mw + 1) { + dev_err(&sndev->stdev->dev, + "Error enumerating crosslink partition\n"); + return -EINVAL; + } + + addr = bar_addrs[0]; + rc = config_rsvd_lut_win(sndev, sndev->mmio_self_ctrl, ntb_lut_idx, + sndev->peer_partition, addr); + if (rc) + return rc; + + rc = crosslink_setup_mws(sndev, ntb_lut_idx, &bar_addrs[1], + bar_cnt - 1); + if (rc) + return rc; + + rc = crosslink_setup_req_ids(sndev, sndev->mmio_peer_ctrl); + if (rc) + return rc; + + sndev->mmio_xlink_win = pci_iomap_range(sndev->stdev->pdev, bar, + LUT_SIZE, LUT_SIZE); + if (!sndev->mmio_xlink_win) { + rc = -ENOMEM; + return rc; + } + + sndev->nr_rsvd_luts++; + + return 0; +} + +static void switchtec_ntb_deinit_crosslink(struct switchtec_ntb *sndev) +{ + if (sndev->mmio_xlink_win) + pci_iounmap(sndev->stdev->pdev, sndev->mmio_xlink_win); +} + static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) { int i; @@ -1222,17 +1406,22 @@ static int switchtec_ntb_add(struct device *dev, goto free_and_exit; switchtec_ntb_init_mw(sndev); - switchtec_ntb_init_db(sndev); - switchtec_ntb_init_msgs(sndev); rc = switchtec_ntb_init_req_id_table(sndev); if (rc) goto free_and_exit; - rc = switchtec_ntb_init_shared_mw(sndev); + rc = switchtec_ntb_init_crosslink(sndev); if (rc) goto free_and_exit; + switchtec_ntb_init_db(sndev); + switchtec_ntb_init_msgs(sndev); + + rc = switchtec_ntb_init_shared_mw(sndev); + if (rc) + goto deinit_crosslink; + rc = switchtec_ntb_init_db_msg_irq(sndev); if (rc) goto deinit_shared_and_exit; @@ -1251,6 +1440,8 @@ deinit_and_exit: switchtec_ntb_deinit_db_msg_irq(sndev); deinit_shared_and_exit: switchtec_ntb_deinit_shared_mw(sndev); +deinit_crosslink: + switchtec_ntb_deinit_crosslink(sndev); free_and_exit: kfree(sndev); dev_err(dev, "failed to register ntb device: %d\n", rc); @@ -1271,6 +1462,7 @@ void switchtec_ntb_remove(struct device *dev, ntb_unregister_device(&sndev->ntb); switchtec_ntb_deinit_db_msg_irq(sndev); switchtec_ntb_deinit_shared_mw(sndev); + switchtec_ntb_deinit_crosslink(sndev); kfree(sndev); dev_info(dev, "ntb device unregistered\n"); } -- cgit From 270d32e63c70c808a91449da24324e0009827c5f Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Wed, 29 Nov 2017 10:55:30 -0700 Subject: ntb_hw_switchtec: Crosslink doorbells and messages In a crosslink configuration doorbells and messages largely work the same but the NTB registers must be accessed through the reserved LUT window. Also, as a bonus, seeing there are now two independent sets of NTB links, both partitions can actually use all 60 doorbell registers instead of them having to be split into two for each partition. Signed-off-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 65 ++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 17db0f50bb22..145b31209f20 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -94,6 +94,7 @@ struct switchtec_ntb { struct ntb_ctrl_regs __iomem *mmio_self_ctrl; struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; + struct ntb_dbmsg_regs __iomem *mmio_peer_dbmsg; void __iomem *mmio_xlink_win; @@ -188,10 +189,10 @@ static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, u32 val) { - if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg)) + if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_peer_dbmsg->omsg)) return -EINVAL; - iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg); + iowrite32(val, &sndev->mmio_peer_dbmsg->omsg[idx].msg); return 0; } @@ -474,6 +475,25 @@ static int crosslink_is_enabled(struct switchtec_ntb *sndev) return ioread8(&inf->ntp_info[sndev->peer_partition].xlink_enabled); } +static void crosslink_init_dbmsgs(struct switchtec_ntb *sndev) +{ + int i; + u32 msg_map = 0; + + if (!crosslink_is_enabled(sndev)) + return; + + for (i = 0; i < ARRAY_SIZE(sndev->mmio_peer_dbmsg->imsg); i++) { + int m = i | sndev->self_partition << 2; + + msg_map |= m << i * 8; + } + + iowrite32(msg_map, &sndev->mmio_peer_dbmsg->msg_map); + iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, + &sndev->mmio_peer_dbmsg->odb_mask); +} + enum { LINK_MESSAGE = 0, MSG_LINK_UP = 1, @@ -504,6 +524,9 @@ static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) ntb_link_event(&sndev->ntb); dev_info(&sndev->stdev->dev, "ntb link %s\n", link_sta ? "up" : "down"); + + if (link_sta) + crosslink_init_dbmsgs(sndev); } } @@ -649,7 +672,7 @@ static int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb, struct switchtec_ntb *sndev = ntb_sndev(ntb); unsigned long offset; - offset = (unsigned long)sndev->mmio_self_dbmsg->odb - + offset = (unsigned long)sndev->mmio_peer_dbmsg->odb - (unsigned long)sndev->stdev->mmio; offset += sndev->db_shift / 8; @@ -667,7 +690,7 @@ static int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) struct switchtec_ntb *sndev = ntb_sndev(ntb); iowrite64(db_bits << sndev->db_peer_shift, - &sndev->mmio_self_dbmsg->odb); + &sndev->mmio_peer_dbmsg->odb); return 0; } @@ -852,6 +875,7 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; + sndev->mmio_peer_dbmsg = sndev->mmio_self_dbmsg; return 0; } @@ -1072,6 +1096,7 @@ static int switchtec_ntb_init_crosslink(struct switchtec_ntb *sndev) const int ntb_lut_idx = 1; u64 bar_addrs[6]; u64 addr; + int offset; int bar_cnt; if (!crosslink_is_enabled(sndev)) @@ -1087,7 +1112,13 @@ static int switchtec_ntb_init_crosslink(struct switchtec_ntb *sndev) return -EINVAL; } - addr = bar_addrs[0]; + addr = (bar_addrs[0] + SWITCHTEC_GAS_NTB_OFFSET + + SWITCHTEC_NTB_REG_DBMSG_OFFSET + + sizeof(struct ntb_dbmsg_regs) * sndev->peer_partition); + + offset = addr & (LUT_SIZE - 1); + addr -= offset; + rc = config_rsvd_lut_win(sndev, sndev->mmio_self_ctrl, ntb_lut_idx, sndev->peer_partition, addr); if (rc) @@ -1109,8 +1140,11 @@ static int switchtec_ntb_init_crosslink(struct switchtec_ntb *sndev) return rc; } + sndev->mmio_peer_dbmsg = sndev->mmio_xlink_win + offset; sndev->nr_rsvd_luts++; + crosslink_init_dbmsgs(sndev); + return 0; } @@ -1163,24 +1197,35 @@ static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) * shared among all partitions. So we must split them in half * (32 for each partition). However, the message interrupts are * also shared with the top 4 doorbells so we just limit this to - * 28 doorbells per partition + * 28 doorbells per partition. + * + * In crosslink mode, each side has it's own dbmsg register so + * they can each use all 60 of the available doorbells. */ static void switchtec_ntb_init_db(struct switchtec_ntb *sndev) { - sndev->db_valid_mask = 0x0FFFFFFF; + sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL; - if (sndev->self_partition < sndev->peer_partition) { + if (sndev->mmio_peer_dbmsg != sndev->mmio_self_dbmsg) { + sndev->db_shift = 0; + sndev->db_peer_shift = 0; + sndev->db_valid_mask = sndev->db_mask; + } else if (sndev->self_partition < sndev->peer_partition) { sndev->db_shift = 0; sndev->db_peer_shift = 32; + sndev->db_valid_mask = 0x0FFFFFFF; } else { sndev->db_shift = 32; sndev->db_peer_shift = 0; + sndev->db_valid_mask = 0x0FFFFFFF; } - sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL; iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, - &sndev->mmio_self_dbmsg->odb_mask); + &sndev->mmio_peer_dbmsg->odb_mask); + + dev_dbg(&sndev->stdev->dev, "dbs: shift %d/%d, mask %016llx\n", + sndev->db_shift, sndev->db_peer_shift, sndev->db_valid_mask); } static void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev) -- cgit From d04be142b8b61ffb3c9cc5c6d1abda8fc59a16c9 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Mon, 4 Dec 2017 10:57:21 -0700 Subject: ntb_hw_switchtec: Force down the link before initializing If one host crashes and soft reboots, the other host may not see a link down event. Then when the crashed host comes back up, the surviving host may not know the link was reset and the NTB clients may not work without being reset. To solve this, we send a LINK_FORCE_DOWN message to each peer every time we come up, before we register the NTB device. If a surviving host still thinks the link is up it will take it down immediately. In this way, once the crashed host comes up fully, it will send a regular link up event as per usual and the link will be properly restarted. While we are in the area, this also fixes the MSG_LINK_UP message that was in the link down function that was reported by Doug Meyers. Signed-off-by: Logan Gunthorpe Reported-by: ThanhTuThai Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 57 +++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 145b31209f20..bcd5b6fb3800 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -122,6 +122,7 @@ struct switchtec_ntb { bool link_is_up; enum ntb_speed link_speed; enum ntb_width link_width; + struct work_struct link_reinit_work; }; static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) @@ -494,18 +495,43 @@ static void crosslink_init_dbmsgs(struct switchtec_ntb *sndev) &sndev->mmio_peer_dbmsg->odb_mask); } -enum { +enum switchtec_msg { LINK_MESSAGE = 0, MSG_LINK_UP = 1, MSG_LINK_DOWN = 2, MSG_CHECK_LINK = 3, + MSG_LINK_FORCE_DOWN = 4, }; -static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) +static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); + +static void link_reinit_work(struct work_struct *work) +{ + struct switchtec_ntb *sndev; + + sndev = container_of(work, struct switchtec_ntb, link_reinit_work); + + switchtec_ntb_reinit_peer(sndev); +} + +static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, + enum switchtec_msg msg) { int link_sta; int old = sndev->link_is_up; + if (msg == MSG_LINK_FORCE_DOWN) { + schedule_work(&sndev->link_reinit_work); + + if (sndev->link_is_up) { + sndev->link_is_up = 0; + ntb_link_event(&sndev->ntb); + dev_info(&sndev->stdev->dev, "ntb link forced down\n"); + } + + return; + } + link_sta = sndev->self_shared->link_sta; if (link_sta) { u64 peer = ioread64(&sndev->peer_shared->magic); @@ -534,7 +560,7 @@ static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) { struct switchtec_ntb *sndev = stdev->sndev; - switchtec_ntb_check_link(sndev); + switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); } static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, @@ -562,7 +588,7 @@ static int switchtec_ntb_link_enable(struct ntb_dev *ntb, sndev->self_shared->link_sta = 1; switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); - switchtec_ntb_check_link(sndev); + switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); return 0; } @@ -574,9 +600,9 @@ static int switchtec_ntb_link_disable(struct ntb_dev *ntb) dev_dbg(&sndev->stdev->dev, "disabling link\n"); sndev->self_shared->link_sta = 0; - switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); + switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); - switchtec_ntb_check_link(sndev); + switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); return 0; } @@ -822,6 +848,8 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) sndev->ntb.topo = NTB_TOPO_SWITCH; sndev->ntb.ops = &switchtec_ntb_ops; + INIT_WORK(&sndev->link_reinit_work, link_reinit_work); + sndev->self_partition = sndev->stdev->partition; sndev->mmio_ntb = sndev->stdev->mmio_ntb; @@ -1368,7 +1396,7 @@ static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev) iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); if (i == LINK_MESSAGE) - switchtec_ntb_check_link(sndev); + switchtec_ntb_check_link(sndev, msg); } } @@ -1429,6 +1457,14 @@ static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) free_irq(sndev->message_irq, sndev); } +static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) +{ + dev_info(&sndev->stdev->dev, "peer reinitialized\n"); + switchtec_ntb_deinit_shared_mw(sndev); + switchtec_ntb_init_mw(sndev); + return switchtec_ntb_init_shared_mw(sndev); +} + static int switchtec_ntb_add(struct device *dev, struct class_interface *class_intf) { @@ -1471,6 +1507,13 @@ static int switchtec_ntb_add(struct device *dev, if (rc) goto deinit_shared_and_exit; + /* + * If this host crashed, the other host may think the link is + * still up. Tell them to force it down (it will go back up + * once we register the ntb device). + */ + switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_FORCE_DOWN); + rc = ntb_register_device(&sndev->ntb); if (rc) goto deinit_and_exit; -- cgit From cbd27448faff4843ac4b66cc71445a10623ff48d Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Mon, 18 Dec 2017 11:25:05 -0700 Subject: ntb_transport: Fix bug with max_mw_size parameter When using the max_mw_size parameter of ntb_transport to limit the size of the Memory windows, communication cannot be established and the queues freeze. This is because the mw_size that's reported to the peer is correctly limited but the size used locally is not. So the MW is initialized with a buffer smaller than the window but the TX side is using the full window. This means the TX side will be writing to a region of the window that points nowhere. This is easily fixed by applying the same limit to tx_size in ntb_transport_init_queue(). Fixes: e26a5843f7f5 ("NTB: Split ntb_hw_intel and ntb_transport drivers") Signed-off-by: Logan Gunthorpe Acked-by: Allen Hubbe Cc: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 045e3dd4750e..9878c48826e3 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1003,6 +1003,9 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, mw_base = nt->mw_vec[mw_num].phys_addr; mw_size = nt->mw_vec[mw_num].phys_size; + if (max_mw_size && mw_size > max_mw_size) + mw_size = max_mw_size; + tx_size = (unsigned int)mw_size / num_qps_mw; qp_offset = tx_size * (qp_num / mw_count); -- cgit From 1e2fd202f8593985cdadca32e0c322f98e7fe7cb Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Mon, 18 Dec 2017 11:25:06 -0700 Subject: ntb_hw_switchtec: Check for alignment of the buffer in mw_set_trans() With Switchtec hardware, the buffer used for a memory window must be aligned to its size (the hardware only replaces the lower bits). In certain circumstances dma_alloc_coherent() will not provide a buffer that adheres to this requirement like when using the CMA and CONFIG_CMA_ALIGNMENT is set lower than the buffer size. When we get an unaligned buffer mw_set_trans() should return an error. We also log an error so we know the cause of the problem. Signed-off-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index bcd5b6fb3800..6c6f991999b5 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -320,6 +320,19 @@ static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, if (xlate_pos < 12) return -EINVAL; + if (!IS_ALIGNED(addr, BIT_ULL(xlate_pos))) { + /* + * In certain circumstances we can get a buffer that is + * not aligned to its size. (Most of the time + * dma_alloc_coherent ensures this). This can happen when + * using large buffers allocated by the CMA + * (see CMA_CONFIG_ALIGNMENT) + */ + dev_err(&sndev->stdev->dev, + "ERROR: Memory window address is not aligned to it's size!\n"); + return -EINVAL; + } + rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, NTB_CTRL_PART_STATUS_LOCKED); if (rc) -- cgit From c6fad21a8d03167a47fc376a64df785d8f6e7385 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 16 Jan 2018 14:50:51 +0100 Subject: ntb_hw_switchtec: fix logic error Newer gcc (version 7 and 8 presumably) warn about a statement mixing the << operator with logical and: drivers/ntb/hw/mscc/ntb_hw_switchtec.c: In function 'switchtec_ntb_init_sndev': drivers/ntb/hw/mscc/ntb_hw_switchtec.c:888:24: error: '<<' in boolean context, did you mean '<' ? [-Werror=int-in-bool-context] My interpretation here is that the author must have intended a bitmask rather than a comparison, so I'm changing the '&&' to '&', which makes a lot more sense in the context. Fixes: 1b249475275d ("ntb_hw_switchtec: Allow using Switchtec NTB in multi-partition setups") Reviewed-by: Logan Gunthorpe Signed-off-by: Arnd Bergmann Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 6c6f991999b5..a1d547b6aa12 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -898,7 +898,7 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) } sndev->peer_partition = ffs(tpart_vec) - 1; - if (!(part_map && (1 << sndev->peer_partition))) { + if (!(part_map & (1 << sndev->peer_partition))) { dev_err(&sndev->stdev->dev, "ntb target partition is not NT partition\n"); return -ENODEV; -- cgit From b87ab21935d76922362ff98a5a78f16e2e956ead Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 6 Dec 2017 17:31:52 +0300 Subject: NTB: Rename NTB messaging API methods There is a common methods signature form used over all the NTB API like functions naming scheme, arguments names and order, etc. Recently added NTB messaging API IO callbacks were named a bit different so should be renamed to be in compliance with the rest of the API. Signed-off-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/hw/idt/ntb_hw_idt.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index 0cd79f367f7c..24040317bb9c 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -1744,20 +1744,19 @@ static int idt_ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits) * idt_ntb_msg_read() - read message register with specified index * (NTB API callback) * @ntb: NTB device context. - * @midx: Message register index * @pidx: OUT - Port index of peer device a message retrieved from - * @msg: OUT - Data + * @midx: Message register index * * Read data from the specified message register and source register. * - * Return: zero on success, negative error if invalid argument passed. + * Return: inbound message register value. */ -static int idt_ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg) +static u32 idt_ntb_msg_read(struct ntb_dev *ntb, int *pidx, int midx) { struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); if (midx < 0 || IDT_MSG_CNT <= midx) - return -EINVAL; + return ~(u32)0; /* Retrieve source port index of the message */ if (pidx != NULL) { @@ -1772,18 +1771,15 @@ static int idt_ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg) } /* Retrieve data of the corresponding message register */ - if (msg != NULL) - *msg = idt_nt_read(ndev, ntdata_tbl.msgs[midx].in); - - return 0; + return idt_nt_read(ndev, ntdata_tbl.msgs[midx].in); } /* - * idt_ntb_msg_write() - write data to the specified message register - * (NTB API callback) + * idt_ntb_peer_msg_write() - write data to the specified message register + * (NTB API callback) * @ntb: NTB device context. - * @midx: Message register index * @pidx: Port index of peer device a message being sent to + * @midx: Message register index * @msg: Data to send * * Just try to send data to a peer. Message status register should be @@ -1791,7 +1787,8 @@ static int idt_ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg) * * Return: zero on success, negative error if invalid argument passed. */ -static int idt_ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx, u32 msg) +static int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx, + u32 msg) { struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); unsigned long irqflags; @@ -2058,7 +2055,7 @@ static const struct ntb_dev_ops idt_ntb_ops = { .msg_set_mask = idt_ntb_msg_set_mask, .msg_clear_mask = idt_ntb_msg_clear_mask, .msg_read = idt_ntb_msg_read, - .msg_write = idt_ntb_msg_write + .peer_msg_write = idt_ntb_peer_msg_write }; /* @@ -2269,7 +2266,7 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf, "Message data:\n"); for (idx = 0; idx < IDT_MSG_CNT; idx++) { int src; - (void)idt_ntb_msg_read(&ndev->ntb, idx, &src, &data); + data = idt_ntb_msg_read(&ndev->ntb, &src, idx); off += scnprintf(strbuf + off, size - off, "\t%hhu. 0x%08x from peer %hhu (Port %hhu)\n", idx, data, src, ndev->peers[src].port); -- cgit From 417cf39cfea9c680aa7c278c8d8a0ca879cacf0a Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 6 Dec 2017 17:31:53 +0300 Subject: NTB: Set dma mask and dma coherent mask to NTB devices The dma_mask and dma_coherent_mask fields of the NTB struct device weren't initialized in hardware drivers. In fact it should be done instead of PCIe interface usage, since NTB clients are supposed to use NTB API and left unaware of real hardware implementation. In addition to that ntb_device_register() method shouldn't clear the passed ntb_dev structure, since it dma_mask is initialized by hardware drivers. Signed-off-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/hw/amd/ntb_hw_amd.c | 4 ++++ drivers/ntb/hw/idt/ntb_hw_idt.c | 8 +++++++- drivers/ntb/hw/intel/ntb_hw_intel.c | 4 ++++ drivers/ntb/ntb.c | 1 - 4 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c index f0788aae05c9..3cfa46876239 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.c +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c @@ -1020,6 +1020,10 @@ static int amd_ntb_init_pci(struct amd_ntb_dev *ndev, goto err_dma_mask; dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); } + rc = dma_coerce_mask_and_coherent(&ndev->ntb.dev, + dma_get_mask(&pdev->dev)); + if (rc) + goto err_dma_mask; ndev->self_mmio = pci_iomap(pdev, 0, 0); if (!ndev->self_mmio) { diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index 24040317bb9c..93d4c9d2a9ad 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -2426,7 +2426,7 @@ static int idt_init_pci(struct idt_ntb_dev *ndev) struct pci_dev *pdev = ndev->ntb.pdev; int ret; - /* Initialize the bit mask of DMA */ + /* Initialize the bit mask of PCI/NTB DMA */ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (ret != 0) { ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); @@ -2447,6 +2447,12 @@ static int idt_init_pci(struct idt_ntb_dev *ndev) dev_warn(&pdev->dev, "Cannot set consistent DMA highmem bit mask\n"); } + ret = dma_coerce_mask_and_coherent(&ndev->ntb.dev, + dma_get_mask(&pdev->dev)); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to set NTB device DMA bit mask\n"); + return ret; + } /* * Enable the device advanced error reporting. It's not critical to diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 341a3d5baa3f..156b45cd4a19 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -2334,6 +2334,10 @@ static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev) goto err_dma_mask; dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); } + rc = dma_coerce_mask_and_coherent(&ndev->ntb.dev, + dma_get_mask(&pdev->dev)); + if (rc) + goto err_dma_mask; ndev->self_mmio = pci_iomap(pdev, 0, 0); if (!ndev->self_mmio) { diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c index bdcd59b13c1f..2581ab724c34 100644 --- a/drivers/ntb/ntb.c +++ b/drivers/ntb/ntb.c @@ -111,7 +111,6 @@ int ntb_register_device(struct ntb_dev *ntb) init_completion(&ntb->released); - memset(&ntb->dev, 0, sizeof(ntb->dev)); ntb->dev.bus = &ntb_bus; ntb->dev.parent = &ntb->pdev->dev; ntb->dev.release = ntb_dev_release; -- cgit From c7aeb0afdcc2d1ec5945e164d3fb97c5ae3edd1a Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 6 Dec 2017 17:31:55 +0300 Subject: NTB: ntb_pp: Add full multi-port NTB API support Current Ping Pong driver can't truly work with multi-port devices. Additionally it requires the Scratchpad registers being available on NTB device. This patches rewrites the driver so one would perform the cyclic Ping-Pong algorithm around all the available NTB peers and makes it working with NTB hardware, which doesn't support Scratchpads, but such alternative as NTB Message register. Additional cleanups are also added here. Signed-off-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/test/ntb_pingpong.c | 447 +++++++++++++++++++++++++--------------- 1 file changed, 282 insertions(+), 165 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c index e700873e03fb..65865e460ab8 100644 --- a/drivers/ntb/test/ntb_pingpong.c +++ b/drivers/ntb/test/ntb_pingpong.c @@ -1,10 +1,11 @@ /* - * This file is provided under a dual BSD/GPLv2 license. When using or + * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * Copyright (C) 2017 T-Platforms. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,6 +19,7 @@ * BSD LICENSE * * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * Copyright (C) 2017 T-Platforms. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,36 +48,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * PCIe NTB Pingpong Linux driver - * - * Contact Information: - * Allen Hubbe */ -/* Note: load this module with option 'dyndbg=+p' */ +/* + * How to use this tool, by example. + * + * Assuming $DBG_DIR is something like: + * '/sys/kernel/debug/ntb_perf/0000:00:03.0' + * Suppose aside from local device there is at least one remote device + * connected to NTB with index 0. + *----------------------------------------------------------------------------- + * Eg: install driver with specified delay between doorbell event and response + * + * root@self# insmod ntb_pingpong.ko delay_ms=1000 + *----------------------------------------------------------------------------- + * Eg: get number of ping-pong cycles performed + * + * root@self# cat $DBG_DIR/count + */ #include #include #include +#include +#include -#include #include #include -#include +#include #include #include -#define DRIVER_NAME "ntb_pingpong" -#define DRIVER_DESCRIPTION "PCIe NTB Simple Pingpong Client" - -#define DRIVER_VERSION "1.0" -#define DRIVER_RELDATE "24 March 2015" -#define DRIVER_AUTHOR "Allen Hubbe " +#define DRIVER_NAME "ntb_pingpong" +#define DRIVER_VERSION "2.0" MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_AUTHOR("Allen Hubbe "); +MODULE_DESCRIPTION("PCIe NTB Simple Pingpong Client"); static unsigned int unsafe; module_param(unsafe, uint, 0644); @@ -85,237 +96,343 @@ static unsigned int delay_ms = 1000; module_param(delay_ms, uint, 0644); MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer"); -static unsigned long db_init = 0x7; -module_param(db_init, ulong, 0644); -MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer"); - -/* Only two-ports NTB devices are supported */ -#define PIDX NTB_DEF_PEER_IDX - struct pp_ctx { - struct ntb_dev *ntb; - u64 db_bits; - /* synchronize access to db_bits by ping and pong */ - spinlock_t db_lock; - struct timer_list db_timer; - unsigned long db_delay; - struct dentry *debugfs_node_dir; - struct dentry *debugfs_count; - atomic_t count; + struct ntb_dev *ntb; + struct hrtimer timer; + u64 in_db; + u64 out_db; + int out_pidx; + u64 nmask; + u64 pmask; + atomic_t count; + spinlock_t lock; + struct dentry *dbgfs_dir; }; +#define to_pp_timer(__timer) \ + container_of(__timer, struct pp_ctx, timer) -static struct dentry *pp_debugfs_dir; +static struct dentry *pp_dbgfs_topdir; -static void pp_ping(struct timer_list *t) +static int pp_find_next_peer(struct pp_ctx *pp) { - struct pp_ctx *pp = from_timer(pp, t, db_timer); - unsigned long irqflags; - u64 db_bits, db_mask; - u32 spad_rd, spad_wr; + u64 link, out_db; + int pidx; + + link = ntb_link_is_up(pp->ntb, NULL, NULL); + + /* Find next available peer */ + if (link & pp->nmask) { + pidx = __ffs64(link & pp->nmask); + out_db = BIT_ULL(pidx + 1); + } else if (link & pp->pmask) { + pidx = __ffs64(link & pp->pmask); + out_db = BIT_ULL(pidx); + } else { + return -ENODEV; + } - spin_lock_irqsave(&pp->db_lock, irqflags); - { - db_mask = ntb_db_valid_mask(pp->ntb); - db_bits = ntb_db_read(pp->ntb); + spin_lock(&pp->lock); + pp->out_pidx = pidx; + pp->out_db = out_db; + spin_unlock(&pp->lock); - if (db_bits) { - dev_dbg(&pp->ntb->dev, - "Masked pongs %#llx\n", - db_bits); - ntb_db_clear(pp->ntb, db_bits); - } + return 0; +} - db_bits = ((pp->db_bits | db_bits) << 1) & db_mask; +static void pp_setup(struct pp_ctx *pp) +{ + int ret; - if (!db_bits) - db_bits = db_init; + ntb_db_set_mask(pp->ntb, pp->in_db); - spad_rd = ntb_spad_read(pp->ntb, 0); - spad_wr = spad_rd + 1; + hrtimer_cancel(&pp->timer); - dev_dbg(&pp->ntb->dev, - "Ping bits %#llx read %#x write %#x\n", - db_bits, spad_rd, spad_wr); + ret = pp_find_next_peer(pp); + if (ret == -ENODEV) { + dev_dbg(&pp->ntb->dev, "Got no peers, so cancel\n"); + return; + } - ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr); - ntb_peer_db_set(pp->ntb, db_bits); - ntb_db_clear_mask(pp->ntb, db_mask); + dev_dbg(&pp->ntb->dev, "Ping-pong started with port %d, db %#llx\n", + ntb_peer_port_number(pp->ntb, pp->out_pidx), pp->out_db); - pp->db_bits = 0; - } - spin_unlock_irqrestore(&pp->db_lock, irqflags); + hrtimer_start(&pp->timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); } -static void pp_link_event(void *ctx) +static void pp_clear(struct pp_ctx *pp) { - struct pp_ctx *pp = ctx; + hrtimer_cancel(&pp->timer); - if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) { - dev_dbg(&pp->ntb->dev, "link is up\n"); - pp_ping(&pp->db_timer); - } else { - dev_dbg(&pp->ntb->dev, "link is down\n"); - del_timer(&pp->db_timer); - } + ntb_db_set_mask(pp->ntb, pp->in_db); + + dev_dbg(&pp->ntb->dev, "Ping-pong cancelled\n"); } -static void pp_db_event(void *ctx, int vec) +static void pp_ping(struct pp_ctx *pp) { - struct pp_ctx *pp = ctx; - u64 db_bits, db_mask; - unsigned long irqflags; + u32 count; - spin_lock_irqsave(&pp->db_lock, irqflags); - { - db_mask = ntb_db_vector_mask(pp->ntb, vec); - db_bits = db_mask & ntb_db_read(pp->ntb); - ntb_db_set_mask(pp->ntb, db_mask); - ntb_db_clear(pp->ntb, db_bits); + count = atomic_read(&pp->count); - pp->db_bits |= db_bits; + spin_lock(&pp->lock); + ntb_peer_spad_write(pp->ntb, pp->out_pidx, 0, count); + ntb_peer_msg_write(pp->ntb, pp->out_pidx, 0, count); - mod_timer(&pp->db_timer, jiffies + pp->db_delay); + dev_dbg(&pp->ntb->dev, "Ping port %d spad %#x, msg %#x\n", + ntb_peer_port_number(pp->ntb, pp->out_pidx), count, count); - dev_dbg(&pp->ntb->dev, - "Pong vec %d bits %#llx\n", - vec, db_bits); - atomic_inc(&pp->count); - } - spin_unlock_irqrestore(&pp->db_lock, irqflags); + ntb_peer_db_set(pp->ntb, pp->out_db); + ntb_db_clear_mask(pp->ntb, pp->in_db); + spin_unlock(&pp->lock); } -static int pp_debugfs_setup(struct pp_ctx *pp) +static void pp_pong(struct pp_ctx *pp) { - struct pci_dev *pdev = pp->ntb->pdev; + u32 msg_data = -1, spad_data = -1; + int pidx = 0; - if (!pp_debugfs_dir) - return -ENODEV; + /* Read pong data */ + spad_data = ntb_spad_read(pp->ntb, 0); + msg_data = ntb_msg_read(pp->ntb, &pidx, 0); + ntb_msg_clear_sts(pp->ntb, -1); - pp->debugfs_node_dir = debugfs_create_dir(pci_name(pdev), - pp_debugfs_dir); - if (!pp->debugfs_node_dir) - return -ENODEV; + /* + * Scratchpad and message data may differ, since message register can't + * be rewritten unless status is cleared. Additionally either of them + * might be unsupported + */ + dev_dbg(&pp->ntb->dev, "Pong spad %#x, msg %#x (port %d)\n", + spad_data, msg_data, ntb_peer_port_number(pp->ntb, pidx)); - pp->debugfs_count = debugfs_create_atomic_t("count", S_IRUSR | S_IWUSR, - pp->debugfs_node_dir, - &pp->count); - if (!pp->debugfs_count) - return -ENODEV; + atomic_inc(&pp->count); - return 0; + ntb_db_set_mask(pp->ntb, pp->in_db); + ntb_db_clear(pp->ntb, pp->in_db); + + hrtimer_start(&pp->timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); +} + +static enum hrtimer_restart pp_timer_func(struct hrtimer *t) +{ + struct pp_ctx *pp = to_pp_timer(t); + + pp_ping(pp); + + return HRTIMER_NORESTART; +} + +static void pp_link_event(void *ctx) +{ + struct pp_ctx *pp = ctx; + + pp_setup(pp); +} + +static void pp_db_event(void *ctx, int vec) +{ + struct pp_ctx *pp = ctx; + + pp_pong(pp); } static const struct ntb_ctx_ops pp_ops = { .link_event = pp_link_event, - .db_event = pp_db_event, + .db_event = pp_db_event }; -static int pp_probe(struct ntb_client *client, - struct ntb_dev *ntb) +static int pp_check_ntb(struct ntb_dev *ntb) { - struct pp_ctx *pp; - int rc; + u64 pmask; if (ntb_db_is_unsafe(ntb)) { - dev_dbg(&ntb->dev, "doorbell is unsafe\n"); - if (!unsafe) { - rc = -EINVAL; - goto err_pp; - } - } - - if (ntb_spad_count(ntb) < 1) { - dev_dbg(&ntb->dev, "no enough scratchpads\n"); - rc = -EINVAL; - goto err_pp; + dev_dbg(&ntb->dev, "Doorbell is unsafe\n"); + if (!unsafe) + return -EINVAL; } if (ntb_spad_is_unsafe(ntb)) { - dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); - if (!unsafe) { - rc = -EINVAL; - goto err_pp; - } + dev_dbg(&ntb->dev, "Scratchpad is unsafe\n"); + if (!unsafe) + return -EINVAL; } - if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) - dev_warn(&ntb->dev, "multi-port NTB is unsupported\n"); + pmask = GENMASK_ULL(ntb_peer_port_count(ntb), 0); + if ((ntb_db_valid_mask(ntb) & pmask) != pmask) { + dev_err(&ntb->dev, "Unsupported DB configuration\n"); + return -EINVAL; + } - pp = kmalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) { - rc = -ENOMEM; - goto err_pp; + if (ntb_spad_count(ntb) < 1 && ntb_msg_count(ntb) < 1) { + dev_err(&ntb->dev, "Scratchpads and messages unsupported\n"); + return -EINVAL; + } else if (ntb_spad_count(ntb) < 1) { + dev_dbg(&ntb->dev, "Scratchpads unsupported\n"); + } else if (ntb_msg_count(ntb) < 1) { + dev_dbg(&ntb->dev, "Messages unsupported\n"); } + return 0; +} + +static struct pp_ctx *pp_create_data(struct ntb_dev *ntb) +{ + struct pp_ctx *pp; + + pp = devm_kzalloc(&ntb->dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return ERR_PTR(-ENOMEM); + pp->ntb = ntb; - pp->db_bits = 0; atomic_set(&pp->count, 0); - spin_lock_init(&pp->db_lock); - timer_setup(&pp->db_timer, pp_ping, 0); - pp->db_delay = msecs_to_jiffies(delay_ms); + spin_lock_init(&pp->lock); + hrtimer_init(&pp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + pp->timer.function = pp_timer_func; + + return pp; +} + +static void pp_init_flds(struct pp_ctx *pp) +{ + int pidx, lport, pcnt; + + /* Find global port index */ + lport = ntb_port_number(pp->ntb); + pcnt = ntb_peer_port_count(pp->ntb); + for (pidx = 0; pidx < pcnt; pidx++) { + if (lport < ntb_peer_port_number(pp->ntb, pidx)) + break; + } - rc = ntb_set_ctx(ntb, pp, &pp_ops); - if (rc) - goto err_ctx; + pp->in_db = BIT_ULL(pidx); + pp->pmask = GENMASK_ULL(pidx, 0) >> 1; + pp->nmask = GENMASK_ULL(pcnt - 1, pidx); - rc = pp_debugfs_setup(pp); - if (rc) - goto err_ctx; + dev_dbg(&pp->ntb->dev, "Inbound db %#llx, prev %#llx, next %#llx\n", + pp->in_db, pp->pmask, pp->nmask); +} + +static int pp_mask_events(struct pp_ctx *pp) +{ + u64 db_mask, msg_mask; + int ret; + + db_mask = ntb_db_valid_mask(pp->ntb); + ret = ntb_db_set_mask(pp->ntb, db_mask); + if (ret) + return ret; - ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); - ntb_link_event(ntb); + /* Skip message events masking if unsupported */ + if (ntb_msg_count(pp->ntb) < 1) + return 0; + + msg_mask = ntb_msg_outbits(pp->ntb) | ntb_msg_inbits(pp->ntb); + return ntb_msg_set_mask(pp->ntb, msg_mask); +} + +static int pp_setup_ctx(struct pp_ctx *pp) +{ + int ret; + + ret = ntb_set_ctx(pp->ntb, pp, &pp_ops); + if (ret) + return ret; + + ntb_link_enable(pp->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); + /* Might be not necessary */ + ntb_link_event(pp->ntb); return 0; +} + +static void pp_clear_ctx(struct pp_ctx *pp) +{ + ntb_link_disable(pp->ntb); -err_ctx: - kfree(pp); -err_pp: - return rc; + ntb_clear_ctx(pp->ntb); } -static void pp_remove(struct ntb_client *client, - struct ntb_dev *ntb) +static void pp_setup_dbgfs(struct pp_ctx *pp) +{ + struct pci_dev *pdev = pp->ntb->pdev; + void *ret; + + pp->dbgfs_dir = debugfs_create_dir(pci_name(pdev), pp_dbgfs_topdir); + + ret = debugfs_create_atomic_t("count", 0600, pp->dbgfs_dir, &pp->count); + if (!ret) + dev_warn(&pp->ntb->dev, "DebugFS unsupported\n"); +} + +static void pp_clear_dbgfs(struct pp_ctx *pp) +{ + debugfs_remove_recursive(pp->dbgfs_dir); +} + +static int pp_probe(struct ntb_client *client, struct ntb_dev *ntb) +{ + struct pp_ctx *pp; + int ret; + + ret = pp_check_ntb(ntb); + if (ret) + return ret; + + pp = pp_create_data(ntb); + if (IS_ERR(pp)) + return PTR_ERR(pp); + + pp_init_flds(pp); + + ret = pp_mask_events(pp); + if (ret) + return ret; + + ret = pp_setup_ctx(pp); + if (ret) + return ret; + + pp_setup_dbgfs(pp); + + return 0; +} + +static void pp_remove(struct ntb_client *client, struct ntb_dev *ntb) { struct pp_ctx *pp = ntb->ctx; - debugfs_remove_recursive(pp->debugfs_node_dir); + pp_clear_dbgfs(pp); - ntb_clear_ctx(ntb); - del_timer_sync(&pp->db_timer); - ntb_link_disable(ntb); + pp_clear_ctx(pp); - kfree(pp); + pp_clear(pp); } static struct ntb_client pp_client = { .ops = { .probe = pp_probe, - .remove = pp_remove, - }, + .remove = pp_remove + } }; static int __init pp_init(void) { - int rc; + int ret; if (debugfs_initialized()) - pp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + pp_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); - rc = ntb_register_client(&pp_client); - if (rc) - goto err_client; + ret = ntb_register_client(&pp_client); + if (ret) + debugfs_remove_recursive(pp_dbgfs_topdir); - return 0; - -err_client: - debugfs_remove_recursive(pp_debugfs_dir); - return rc; + return ret; } module_init(pp_init); static void __exit pp_exit(void) { ntb_unregister_client(&pp_client); - debugfs_remove_recursive(pp_debugfs_dir); + debugfs_remove_recursive(pp_dbgfs_topdir); } module_exit(pp_exit); + -- cgit From 7f46c8b3a5523a28cb81c2c12bc3dcc76ed52d59 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 6 Dec 2017 17:31:56 +0300 Subject: NTB: ntb_tool: Add full multi-port NTB API support Former NTB Debugging tool driver supported only the limited functionality of the recently updated NTB API, which is now available to work with the truly NTB multi-port devices and devices, which got NTB Message registers instead of Scratchpads. This patch fully rewrites the driver so one would fully expose all the new NTB API interfaces. Particularly it concerns the Message registers, peer ports API, NTB link settings. Additional cleanups are also added here. Signed-off-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/test/ntb_tool.c | 1820 +++++++++++++++++++++++++++++-------------- 1 file changed, 1240 insertions(+), 580 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c index e490bbc8726c..920fc9b161b0 100644 --- a/drivers/ntb/test/ntb_tool.c +++ b/drivers/ntb/test/ntb_tool.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * Copyright (C) 2017 T-Platforms All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,6 +19,7 @@ * BSD LICENSE * * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * Copyright (C) 2017 T-Platforms All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,9 +48,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * PCIe NTB Debugging Tool Linux driver - * - * Contact Information: - * Allen Hubbe */ /* @@ -56,42 +55,125 @@ * * Assuming $DBG_DIR is something like: * '/sys/kernel/debug/ntb_tool/0000:00:03.0' + * Suppose aside from local device there is at least one remote device + * connected to NTB with index 0. + *----------------------------------------------------------------------------- + * Eg: check local/peer device information. + * + * # Get local device port number + * root@self# cat $DBG_DIR/port + * + * # Check local device functionality + * root@self# ls $DBG_DIR + * db msg1 msg_sts peer4/ port + * db_event msg2 peer0/ peer5/ spad0 + * db_mask msg3 peer1/ peer_db spad1 + * link msg_event peer2/ peer_db_mask spad2 + * msg0 msg_mask peer3/ peer_spad spad3 + * # As one can see it supports: + * # 1) four inbound message registers + * # 2) four inbound scratchpads + * # 3) up to six peer devices + * + * # Check peer device port number + * root@self# cat $DBG_DIR/peer0/port * - * Eg: check if clearing the doorbell mask generates an interrupt. + * # Check peer device(s) functionality to be used + * root@self# ls $DBG_DIR/peer0 + * link mw_trans0 mw_trans6 port + * link_event mw_trans1 mw_trans7 spad0 + * msg0 mw_trans2 peer_mw_trans0 spad1 + * msg1 mw_trans3 peer_mw_trans1 spad2 + * msg2 mw_trans4 peer_mw_trans2 spad3 + * msg3 mw_trans5 peer_mw_trans3 + * # As one can see we got: + * # 1) four outbound message registers + * # 2) four outbound scratchpads + * # 3) eight inbound memory windows + * # 4) four outbound memory windows + *----------------------------------------------------------------------------- + * Eg: NTB link tests * - * # Check the link status - * root@self# cat $DBG_DIR/link + * # Set local link up/down + * root@self# echo Y > $DBG_DIR/link + * root@self# echo N > $DBG_DIR/link * - * # Block until the link is up - * root@self# echo Y > $DBG_DIR/link_event + * # Check if link with peer device is up/down: + * root@self# cat $DBG_DIR/peer0/link * - * # Set the doorbell mask - * root@self# echo 's 1' > $DBG_DIR/mask + * # Block until the link is up/down + * root@self# echo Y > $DBG_DIR/peer0/link_event + * root@self# echo N > $DBG_DIR/peer0/link_event + *----------------------------------------------------------------------------- + * Eg: Doorbell registers tests (some functionality might be absent) * - * # Ring the doorbell from the peer + * # Set/clear/get local doorbell + * root@self# echo 's 1' > $DBG_DIR/db + * root@self# echo 'c 1' > $DBG_DIR/db + * root@self# cat $DBG_DIR/db + * + * # Set/clear/get local doorbell mask + * root@self# echo 's 1' > $DBG_DIR/db_mask + * root@self# echo 'c 1' > $DBG_DIR/db_mask + * root@self# cat $DBG_DIR/db_mask + * + * # Ring/clear/get peer doorbell * root@peer# echo 's 1' > $DBG_DIR/peer_db + * root@peer# echo 'c 1' > $DBG_DIR/peer_db + * root@peer# cat $DBG_DIR/peer_db + * + * # Set/clear/get peer doorbell mask + * root@self# echo 's 1' > $DBG_DIR/peer_db_mask + * root@self# echo 'c 1' > $DBG_DIR/peer_db_mask + * root@self# cat $DBG_DIR/peer_db_mask + * + * # Block until local doorbell is set with specified value + * root@self# echo 1 > $DBG_DIR/db_event + *----------------------------------------------------------------------------- + * Eg: Message registers tests (functionality might be absent) * - * # Clear the doorbell mask - * root@self# echo 'c 1' > $DBG_DIR/mask + * # Set/clear/get in/out message registers status + * root@self# echo 's 1' > $DBG_DIR/msg_sts + * root@self# echo 'c 1' > $DBG_DIR/msg_sts + * root@self# cat $DBG_DIR/msg_sts * - * Observe debugging output in dmesg or your console. You should see a - * doorbell event triggered by clearing the mask. If not, this may indicate an - * issue with the hardware that needs to be worked around in the driver. + * # Set/clear in/out message registers mask + * root@self# echo 's 1' > $DBG_DIR/msg_mask + * root@self# echo 'c 1' > $DBG_DIR/msg_mask * - * Eg: read and write scratchpad registers + * # Get inbound message register #0 value and source of port index + * root@self# cat $DBG_DIR/msg0 * - * root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad + * # Send some data to peer over outbound message register #0 + * root@self# echo 0x01020304 > $DBG_DIR/peer0/msg0 + *----------------------------------------------------------------------------- + * Eg: Scratchpad registers tests (functionality might be absent) * - * root@self# cat $DBG_DIR/spad + * # Write/read to/from local scratchpad register #0 + * root@peer# echo 0x01020304 > $DBG_DIR/spad0 + * root@peer# cat $DBG_DIR/spad0 * - * Observe that spad 0 and 1 have the values set by the peer. + * # Write/read to/from peer scratchpad register #0 + * root@peer# echo 0x01020304 > $DBG_DIR/peer0/spad0 + * root@peer# cat $DBG_DIR/peer0/spad0 + *----------------------------------------------------------------------------- + * Eg: Memory windows tests * - * # Check the memory window translation info - * cat $DBG_DIR/peer_trans0 + * # Create inbound memory window buffer of specified size/get its base address + * root@peer# echo 16384 > $DBG_DIR/peer0/mw_trans0 + * root@peer# cat $DBG_DIR/peer0/mw_trans0 * - * # Setup a 16k memory window buffer - * echo 16384 > $DBG_DIR/peer_trans0 + * # Write/read data to/from inbound memory window + * root@peer# echo Hello > $DBG_DIR/peer0/mw0 + * root@peer# head -c 7 $DBG_DIR/peer0/mw0 * + * # Map outbound memory window/check it settings (on peer device) + * root@peer# echo 0xADD0BA5E:16384 > $DBG_DIR/peer0/peer_mw_trans0 + * root@peer# cat $DBG_DIR/peer0/peer_mw_trans0 + * + * # Write/read data to/from outbound memory window (on peer device) + * root@peer# echo olleH > $DBG_DIR/peer0/peer_mw0 + * root@peer# head -c 7 $DBG_DIR/peer0/peer_mw0 */ #include @@ -106,48 +188,87 @@ #include -#define DRIVER_NAME "ntb_tool" -#define DRIVER_DESCRIPTION "PCIe NTB Debugging Tool" - -#define DRIVER_VERSION "1.0" -#define DRIVER_RELDATE "22 April 2015" -#define DRIVER_AUTHOR "Allen Hubbe " +#define DRIVER_NAME "ntb_tool" +#define DRIVER_VERSION "2.0" MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESCRIPTION); - -/* It is rare to have hadrware with greater than six MWs */ -#define MAX_MWS 6 -/* Only two-ports devices are supported */ -#define PIDX NTB_DEF_PEER_IDX - -static struct dentry *tool_dbgfs; +MODULE_AUTHOR("Allen Hubbe "); +MODULE_DESCRIPTION("PCIe NTB Debugging Tool"); +/* + * Inbound and outbound memory windows descriptor. Union members selection + * depends on the MW type the structure describes. mm_base/dma_base are the + * virtual and DMA address of an inbound MW. io_base/tr_base are the MMIO + * mapped virtual and xlat addresses of an outbound MW respectively. + */ struct tool_mw { - int idx; + int widx; + int pidx; struct tool_ctx *tc; - resource_size_t win_size; + union { + u8 *mm_base; + u8 __iomem *io_base; + }; + union { + dma_addr_t dma_base; + u64 tr_base; + }; resource_size_t size; - u8 __iomem *local; - u8 *peer; - dma_addr_t peer_dma; - struct dentry *peer_dbg_file; + struct dentry *dbgfs_file; +}; + +/* + * Wrapper structure is used to distinguish the outbound MW peers reference + * within the corresponding DebugFS directory IO operation. + */ +struct tool_mw_wrap { + int pidx; + struct tool_mw *mw; +}; + +struct tool_msg { + int midx; + int pidx; + struct tool_ctx *tc; +}; + +struct tool_spad { + int sidx; + int pidx; + struct tool_ctx *tc; +}; + +struct tool_peer { + int pidx; + struct tool_ctx *tc; + int inmw_cnt; + struct tool_mw *inmws; + int outmw_cnt; + struct tool_mw_wrap *outmws; + int outmsg_cnt; + struct tool_msg *outmsgs; + int outspad_cnt; + struct tool_spad *outspads; + struct dentry *dbgfs_dir; }; struct tool_ctx { struct ntb_dev *ntb; - struct dentry *dbgfs; wait_queue_head_t link_wq; - int mw_count; - struct tool_mw mws[MAX_MWS]; + wait_queue_head_t db_wq; + wait_queue_head_t msg_wq; + int outmw_cnt; + struct tool_mw *outmws; + int peer_cnt; + struct tool_peer *peers; + int inmsg_cnt; + struct tool_msg *inmsgs; + int inspad_cnt; + struct tool_spad *inspads; + struct dentry *dbgfs_dir; }; -#define SPAD_FNAME_SIZE 0x10 -#define INT_PTR(x) ((void *)(unsigned long)x) -#define PTR_INT(x) ((int)(unsigned long)x) - #define TOOL_FOPS_RDWR(__name, __read, __write) \ const struct file_operations __name = { \ .owner = THIS_MODULE, \ @@ -156,6 +277,15 @@ struct tool_ctx { .write = __write, \ } +#define TOOL_BUF_LEN 32 + +static struct dentry *tool_dbgfs_topdir; + +/*============================================================================== + * NTB events handlers + *============================================================================== + */ + static void tool_link_event(void *ctx) { struct tool_ctx *tc = ctx; @@ -181,580 +311,576 @@ static void tool_db_event(void *ctx, int vec) dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", vec, db_mask, db_bits); + + wake_up(&tc->db_wq); +} + +static void tool_msg_event(void *ctx) +{ + struct tool_ctx *tc = ctx; + u64 msg_sts; + + msg_sts = ntb_msg_read_sts(tc->ntb); + + dev_dbg(&tc->ntb->dev, "message bits %#llx\n", msg_sts); + + wake_up(&tc->msg_wq); } static const struct ntb_ctx_ops tool_ops = { .link_event = tool_link_event, .db_event = tool_db_event, + .msg_event = tool_msg_event }; -static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf, - size_t size, loff_t *offp, - u64 (*db_read_fn)(struct ntb_dev *)) +/*============================================================================== + * Common read/write methods + *============================================================================== + */ + +static ssize_t tool_fn_read(struct tool_ctx *tc, char __user *ubuf, + size_t size, loff_t *offp, + u64 (*fn_read)(struct ntb_dev *)) { size_t buf_size; - char *buf; - ssize_t pos, rc; + char buf[TOOL_BUF_LEN]; + ssize_t pos; - if (!db_read_fn) + if (!fn_read) return -EINVAL; - buf_size = min_t(size_t, size, 0x20); - - buf = kmalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pos = scnprintf(buf, buf_size, "%#llx\n", - db_read_fn(tc->ntb)); + buf_size = min(size, sizeof(buf)); - rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); + pos = scnprintf(buf, buf_size, "%#llx\n", fn_read(tc->ntb)); - kfree(buf); - - return rc; + return simple_read_from_buffer(ubuf, size, offp, buf, pos); } -static ssize_t tool_dbfn_write(struct tool_ctx *tc, - const char __user *ubuf, - size_t size, loff_t *offp, - int (*db_set_fn)(struct ntb_dev *, u64), - int (*db_clear_fn)(struct ntb_dev *, u64)) +static ssize_t tool_fn_write(struct tool_ctx *tc, + const char __user *ubuf, + size_t size, loff_t *offp, + int (*fn_set)(struct ntb_dev *, u64), + int (*fn_clear)(struct ntb_dev *, u64)) { - u64 db_bits; char *buf, cmd; - ssize_t rc; + ssize_t ret; + u64 bits; int n; buf = kmalloc(size + 1, GFP_KERNEL); if (!buf) return -ENOMEM; - rc = simple_write_to_buffer(buf, size, offp, ubuf, size); - if (rc < 0) { + ret = simple_write_to_buffer(buf, size, offp, ubuf, size); + if (ret < 0) { kfree(buf); - return rc; + return ret; } buf[size] = 0; - n = sscanf(buf, "%c %lli", &cmd, &db_bits); + n = sscanf(buf, "%c %lli", &cmd, &bits); kfree(buf); if (n != 2) { - rc = -EINVAL; + ret = -EINVAL; } else if (cmd == 's') { - if (!db_set_fn) - rc = -EINVAL; + if (!fn_set) + ret = -EINVAL; else - rc = db_set_fn(tc->ntb, db_bits); + ret = fn_set(tc->ntb, bits); } else if (cmd == 'c') { - if (!db_clear_fn) - rc = -EINVAL; + if (!fn_clear) + ret = -EINVAL; else - rc = db_clear_fn(tc->ntb, db_bits); + ret = fn_clear(tc->ntb, bits); } else { - rc = -EINVAL; + ret = -EINVAL; } - return rc ? : size; + return ret ? : size; } -static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf, - size_t size, loff_t *offp, - u32 (*spad_read_fn)(struct ntb_dev *, int)) -{ - size_t buf_size; - char *buf; - ssize_t pos, rc; - int i, spad_count; - - if (!spad_read_fn) - return -EINVAL; - - spad_count = ntb_spad_count(tc->ntb); +/*============================================================================== + * Port read/write methods + *============================================================================== + */ - /* - * We multiply the number of spads by 15 to get the buffer size - * this is from 3 for the %d, 10 for the largest hex value - * (0x00000000) and 2 for the tab and line feed. - */ - buf_size = min_t(size_t, size, spad_count * 15); +static ssize_t tool_port_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + char buf[TOOL_BUF_LEN]; + int pos; - buf = kmalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; + pos = scnprintf(buf, sizeof(buf), "%d\n", ntb_port_number(tc->ntb)); - pos = 0; + return simple_read_from_buffer(ubuf, size, offp, buf, pos); +} - for (i = 0; i < spad_count; ++i) { - pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n", - i, spad_read_fn(tc->ntb, i)); - } +static TOOL_FOPS_RDWR(tool_port_fops, + tool_port_read, + NULL); - rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); +static ssize_t tool_peer_port_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_peer *peer = filep->private_data; + struct tool_ctx *tc = peer->tc; + char buf[TOOL_BUF_LEN]; + int pos; - kfree(buf); + pos = scnprintf(buf, sizeof(buf), "%d\n", + ntb_peer_port_number(tc->ntb, peer->pidx)); - return rc; + return simple_read_from_buffer(ubuf, size, offp, buf, pos); } -static ssize_t tool_spadfn_write(struct tool_ctx *tc, - const char __user *ubuf, - size_t size, loff_t *offp, - int (*spad_write_fn)(struct ntb_dev *, - int, u32)) +static TOOL_FOPS_RDWR(tool_peer_port_fops, + tool_peer_port_read, + NULL); + +static int tool_init_peers(struct tool_ctx *tc) { - int spad_idx; - u32 spad_val; - char *buf, *buf_ptr; - int pos, n; - ssize_t rc; - - if (!spad_write_fn) { - dev_dbg(&tc->ntb->dev, "no spad write fn\n"); - return -EINVAL; - } + int pidx; - buf = kmalloc(size + 1, GFP_KERNEL); - if (!buf) + tc->peer_cnt = ntb_peer_port_count(tc->ntb); + tc->peers = devm_kcalloc(&tc->ntb->dev, tc->peer_cnt, + sizeof(*tc->peers), GFP_KERNEL); + if (tc->peers == NULL) return -ENOMEM; - rc = simple_write_to_buffer(buf, size, offp, ubuf, size); - if (rc < 0) { - kfree(buf); - return rc; - } - - buf[size] = 0; - buf_ptr = buf; - n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos); - while (n == 2) { - buf_ptr += pos; - rc = spad_write_fn(tc->ntb, spad_idx, spad_val); - if (rc) - break; - - n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos); + for (pidx = 0; pidx < tc->peer_cnt; pidx++) { + tc->peers[pidx].pidx = pidx; + tc->peers[pidx].tc = tc; } - if (n < 0) - rc = n; - - kfree(buf); - - return rc ? : size; + return 0; } -static ssize_t tool_db_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_ctx *tc = filep->private_data; - - return tool_dbfn_read(tc, ubuf, size, offp, - tc->ntb->ops->db_read); -} +/*============================================================================== + * Link state read/write methods + *============================================================================== + */ -static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) +static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) { struct tool_ctx *tc = filep->private_data; + bool val; + int ret; - return tool_dbfn_write(tc, ubuf, size, offp, - tc->ntb->ops->db_set, - tc->ntb->ops->db_clear); -} + ret = kstrtobool_from_user(ubuf, size, &val); + if (ret) + return ret; -static TOOL_FOPS_RDWR(tool_db_fops, - tool_db_read, - tool_db_write); + if (val) + ret = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); + else + ret = ntb_link_disable(tc->ntb); -static ssize_t tool_mask_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_ctx *tc = filep->private_data; + if (ret) + return ret; - return tool_dbfn_read(tc, ubuf, size, offp, - tc->ntb->ops->db_read_mask); + return size; } -static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) +static TOOL_FOPS_RDWR(tool_link_fops, + NULL, + tool_link_write); + +static ssize_t tool_peer_link_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_ctx *tc = filep->private_data; + struct tool_peer *peer = filep->private_data; + struct tool_ctx *tc = peer->tc; + char buf[3]; - return tool_dbfn_write(tc, ubuf, size, offp, - tc->ntb->ops->db_set_mask, - tc->ntb->ops->db_clear_mask); + if (ntb_link_is_up(tc->ntb, NULL, NULL) & BIT(peer->pidx)) + buf[0] = 'Y'; + else + buf[0] = 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + + return simple_read_from_buffer(ubuf, size, offp, buf, 3); } -static TOOL_FOPS_RDWR(tool_mask_fops, - tool_mask_read, - tool_mask_write); +static TOOL_FOPS_RDWR(tool_peer_link_fops, + tool_peer_link_read, + NULL); -static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) +static ssize_t tool_peer_link_event_write(struct file *filep, + const char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_ctx *tc = filep->private_data; + struct tool_peer *peer = filep->private_data; + struct tool_ctx *tc = peer->tc; + u64 link_msk; + bool val; + int ret; - return tool_dbfn_read(tc, ubuf, size, offp, - tc->ntb->ops->peer_db_read); -} + ret = kstrtobool_from_user(ubuf, size, &val); + if (ret) + return ret; -static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_ctx *tc = filep->private_data; + link_msk = BIT_ULL_MASK(peer->pidx); + + if (wait_event_interruptible(tc->link_wq, + !!(ntb_link_is_up(tc->ntb, NULL, NULL) & link_msk) == val)) + return -ERESTART; - return tool_dbfn_write(tc, ubuf, size, offp, - tc->ntb->ops->peer_db_set, - tc->ntb->ops->peer_db_clear); + return size; } -static TOOL_FOPS_RDWR(tool_peer_db_fops, - tool_peer_db_read, - tool_peer_db_write); +static TOOL_FOPS_RDWR(tool_peer_link_event_fops, + NULL, + tool_peer_link_event_write); -static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) +/*============================================================================== + * Memory windows read/write/setting methods + *============================================================================== + */ + +static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_ctx *tc = filep->private_data; + struct tool_mw *inmw = filep->private_data; + + if (inmw->mm_base == NULL) + return -ENXIO; - return tool_dbfn_read(tc, ubuf, size, offp, - tc->ntb->ops->peer_db_read_mask); + return simple_read_from_buffer(ubuf, size, offp, + inmw->mm_base, inmw->size); } -static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) +static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_ctx *tc = filep->private_data; + struct tool_mw *inmw = filep->private_data; + + if (inmw->mm_base == NULL) + return -ENXIO; - return tool_dbfn_write(tc, ubuf, size, offp, - tc->ntb->ops->peer_db_set_mask, - tc->ntb->ops->peer_db_clear_mask); + return simple_write_to_buffer(inmw->mm_base, inmw->size, offp, + ubuf, size); } -static TOOL_FOPS_RDWR(tool_peer_mask_fops, - tool_peer_mask_read, - tool_peer_mask_write); +static TOOL_FOPS_RDWR(tool_mw_fops, + tool_mw_read, + tool_mw_write); -static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) +static int tool_setup_mw(struct tool_ctx *tc, int pidx, int widx, + size_t req_size) { - struct tool_ctx *tc = filep->private_data; + resource_size_t size, addr_align, size_align; + struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; + char buf[TOOL_BUF_LEN]; + int ret; - return tool_spadfn_read(tc, ubuf, size, offp, - tc->ntb->ops->spad_read); -} + if (inmw->mm_base != NULL) + return 0; -static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_ctx *tc = filep->private_data; + ret = ntb_mw_get_align(tc->ntb, pidx, widx, &addr_align, + &size_align, &size); + if (ret) + return ret; + + inmw->size = min_t(resource_size_t, req_size, size); + inmw->size = round_up(inmw->size, addr_align); + inmw->size = round_up(inmw->size, size_align); + inmw->mm_base = dma_alloc_coherent(&tc->ntb->dev, inmw->size, + &inmw->dma_base, GFP_KERNEL); + if (!inmw->mm_base) + return -ENOMEM; - return tool_spadfn_write(tc, ubuf, size, offp, - tc->ntb->ops->spad_write); -} + if (!IS_ALIGNED(inmw->dma_base, addr_align)) { + ret = -ENOMEM; + goto err_free_dma; + } -static TOOL_FOPS_RDWR(tool_spad_fops, - tool_spad_read, - tool_spad_write); + ret = ntb_mw_set_trans(tc->ntb, pidx, widx, inmw->dma_base, inmw->size); + if (ret) + goto err_free_dma; -static u32 ntb_tool_peer_spad_read(struct ntb_dev *ntb, int sidx) -{ - return ntb_peer_spad_read(ntb, PIDX, sidx); -} + snprintf(buf, sizeof(buf), "mw%d", widx); + inmw->dbgfs_file = debugfs_create_file(buf, 0600, + tc->peers[pidx].dbgfs_dir, inmw, + &tool_mw_fops); -static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_ctx *tc = filep->private_data; + return 0; - return tool_spadfn_read(tc, ubuf, size, offp, ntb_tool_peer_spad_read); -} +err_free_dma: + dma_free_coherent(&tc->ntb->dev, inmw->size, inmw->mm_base, + inmw->dma_base); + inmw->mm_base = NULL; + inmw->dma_base = 0; + inmw->size = 0; -static int ntb_tool_peer_spad_write(struct ntb_dev *ntb, int sidx, u32 val) -{ - return ntb_peer_spad_write(ntb, PIDX, sidx, val); + return ret; } -static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) +static void tool_free_mw(struct tool_ctx *tc, int pidx, int widx) { - struct tool_ctx *tc = filep->private_data; - - return tool_spadfn_write(tc, ubuf, size, offp, - ntb_tool_peer_spad_write); -} - -static TOOL_FOPS_RDWR(tool_peer_spad_fops, - tool_peer_spad_read, - tool_peer_spad_write); + struct tool_mw *inmw = &tc->peers[pidx].inmws[widx]; -static ssize_t tool_link_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_ctx *tc = filep->private_data; - char buf[3]; + debugfs_remove(inmw->dbgfs_file); - buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N'; - buf[1] = '\n'; - buf[2] = '\0'; + if (inmw->mm_base != NULL) { + ntb_mw_clear_trans(tc->ntb, pidx, widx); + dma_free_coherent(&tc->ntb->dev, inmw->size, + inmw->mm_base, inmw->dma_base); + } - return simple_read_from_buffer(ubuf, size, offp, buf, 2); + inmw->mm_base = NULL; + inmw->dma_base = 0; + inmw->size = 0; + inmw->dbgfs_file = NULL; } -static ssize_t tool_link_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) +static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_ctx *tc = filep->private_data; - char buf[32]; + struct tool_mw *inmw = filep->private_data; + resource_size_t addr_align; + resource_size_t size_align; + resource_size_t size_max; + ssize_t ret, off = 0; size_t buf_size; - bool val; - int rc; + char *buf; - buf_size = min(size, (sizeof(buf) - 1)); - if (copy_from_user(buf, ubuf, buf_size)) - return -EFAULT; + buf_size = min_t(size_t, size, 512); - buf[buf_size] = '\0'; + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - rc = strtobool(buf, &val); - if (rc) - return rc; + ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx, + &addr_align, &size_align, &size_max); + if (ret) + return ret; - if (val) - rc = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); - else - rc = ntb_link_disable(tc->ntb); + off += scnprintf(buf + off, buf_size - off, + "Inbound MW \t%d\n", + inmw->widx); - if (rc) - return rc; + off += scnprintf(buf + off, buf_size - off, + "Port \t%d (%d)\n", + ntb_peer_port_number(inmw->tc->ntb, inmw->pidx), + inmw->pidx); - return size; -} + off += scnprintf(buf + off, buf_size - off, + "Window Address \t0x%pK\n", inmw->mm_base); -static TOOL_FOPS_RDWR(tool_link_fops, - tool_link_read, - tool_link_write); + off += scnprintf(buf + off, buf_size - off, + "DMA Address \t%pad\n", + &inmw->dma_base); -static ssize_t tool_link_event_write(struct file *filep, - const char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_ctx *tc = filep->private_data; - char buf[32]; - size_t buf_size; - bool val; - int rc; + off += scnprintf(buf + off, buf_size - off, + "Window Size \t%pa[p]\n", + &inmw->size); - buf_size = min(size, (sizeof(buf) - 1)); - if (copy_from_user(buf, ubuf, buf_size)) - return -EFAULT; + off += scnprintf(buf + off, buf_size - off, + "Alignment \t%pa[p]\n", + &addr_align); - buf[buf_size] = '\0'; + off += scnprintf(buf + off, buf_size - off, + "Size Alignment \t%pa[p]\n", + &size_align); + + off += scnprintf(buf + off, buf_size - off, + "Size Max \t%pa[p]\n", + &size_max); - rc = strtobool(buf, &val); - if (rc) - return rc; + ret = simple_read_from_buffer(ubuf, size, offp, buf, off); + kfree(buf); - if (wait_event_interruptible(tc->link_wq, - ntb_link_is_up(tc->ntb, NULL, NULL) == val)) - return -ERESTART; + return ret; +} + +static ssize_t tool_mw_trans_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_mw *inmw = filep->private_data; + unsigned int val; + int ret; + + ret = kstrtouint_from_user(ubuf, size, 0, &val); + if (ret) + return ret; + + tool_free_mw(inmw->tc, inmw->pidx, inmw->widx); + if (val) { + ret = tool_setup_mw(inmw->tc, inmw->pidx, inmw->widx, val); + if (ret) + return ret; + } return size; } -static TOOL_FOPS_RDWR(tool_link_event_fops, - NULL, - tool_link_event_write); +static TOOL_FOPS_RDWR(tool_mw_trans_fops, + tool_mw_trans_read, + tool_mw_trans_write); -static ssize_t tool_mw_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) +static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_mw *mw = filep->private_data; - ssize_t rc; + struct tool_mw *outmw = filep->private_data; loff_t pos = *offp; + ssize_t ret; void *buf; - if (mw->local == NULL) + if (outmw->io_base == NULL) return -EIO; - if (pos < 0) - return -EINVAL; - if (pos >= mw->win_size || !size) + + if (pos >= outmw->size || !size) return 0; - if (size > mw->win_size - pos) - size = mw->win_size - pos; + + if (size > outmw->size - pos) + size = outmw->size - pos; buf = kmalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; - memcpy_fromio(buf, mw->local + pos, size); - rc = copy_to_user(ubuf, buf, size); - if (rc == size) { - rc = -EFAULT; + memcpy_fromio(buf, outmw->io_base + pos, size); + ret = copy_to_user(ubuf, buf, size); + if (ret == size) { + ret = -EFAULT; goto err_free; } - size -= rc; + size -= ret; *offp = pos + size; - rc = size; + ret = size; err_free: kfree(buf); - return rc; + return ret; } -static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) +static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_mw *mw = filep->private_data; - ssize_t rc; + struct tool_mw *outmw = filep->private_data; + ssize_t ret; loff_t pos = *offp; void *buf; - if (pos < 0) - return -EINVAL; - if (pos >= mw->win_size || !size) + if (outmw->io_base == NULL) + return -EIO; + + if (pos >= outmw->size || !size) return 0; - if (size > mw->win_size - pos) - size = mw->win_size - pos; + if (size > outmw->size - pos) + size = outmw->size - pos; buf = kmalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; - rc = copy_from_user(buf, ubuf, size); - if (rc == size) { - rc = -EFAULT; + ret = copy_from_user(buf, ubuf, size); + if (ret == size) { + ret = -EFAULT; goto err_free; } - size -= rc; + size -= ret; *offp = pos + size; - rc = size; + ret = size; - memcpy_toio(mw->local + pos, buf, size); + memcpy_toio(outmw->io_base + pos, buf, size); err_free: kfree(buf); - return rc; -} - -static TOOL_FOPS_RDWR(tool_mw_fops, - tool_mw_read, - tool_mw_write); - -static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_mw *mw = filep->private_data; - - if (!mw->peer) - return -ENXIO; - - return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size); -} - -static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, - size_t size, loff_t *offp) -{ - struct tool_mw *mw = filep->private_data; - - if (!mw->peer) - return -ENXIO; - - return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size); + return ret; } static TOOL_FOPS_RDWR(tool_peer_mw_fops, tool_peer_mw_read, tool_peer_mw_write); -static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size) +static int tool_setup_peer_mw(struct tool_ctx *tc, int pidx, int widx, + u64 req_addr, size_t req_size) { - int rc; - struct tool_mw *mw = &tc->mws[idx]; - resource_size_t size, align_addr, align_size; - char buf[16]; + struct tool_mw *outmw = &tc->outmws[widx]; + resource_size_t map_size; + phys_addr_t map_base; + char buf[TOOL_BUF_LEN]; + int ret; - if (mw->peer) + if (outmw->io_base != NULL) return 0; - rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr, - &align_size, &size); - if (rc) - return rc; + ret = ntb_peer_mw_get_addr(tc->ntb, widx, &map_base, &map_size); + if (ret) + return ret; - mw->size = min_t(resource_size_t, req_size, size); - mw->size = round_up(mw->size, align_addr); - mw->size = round_up(mw->size, align_size); - mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size, - &mw->peer_dma, GFP_KERNEL); + ret = ntb_peer_mw_set_trans(tc->ntb, pidx, widx, req_addr, req_size); + if (ret) + return ret; - if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr)) - return -ENOMEM; + outmw->io_base = ioremap_wc(map_base, map_size); + if (outmw->io_base == NULL) { + ret = -EFAULT; + goto err_clear_trans; + } - rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size); - if (rc) - goto err_free_dma; + outmw->tr_base = req_addr; + outmw->size = req_size; + outmw->pidx = pidx; - snprintf(buf, sizeof(buf), "peer_mw%d", idx); - mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR, - mw->tc->dbgfs, mw, - &tool_peer_mw_fops); + snprintf(buf, sizeof(buf), "peer_mw%d", widx); + outmw->dbgfs_file = debugfs_create_file(buf, 0600, + tc->peers[pidx].dbgfs_dir, outmw, + &tool_peer_mw_fops); return 0; -err_free_dma: - dma_free_coherent(&tc->ntb->pdev->dev, mw->size, - mw->peer, - mw->peer_dma); - mw->peer = NULL; - mw->peer_dma = 0; - mw->size = 0; - - return rc; +err_clear_trans: + ntb_peer_mw_clear_trans(tc->ntb, pidx, widx); + + return ret; } -static void tool_free_mw(struct tool_ctx *tc, int idx) +static void tool_free_peer_mw(struct tool_ctx *tc, int widx) { - struct tool_mw *mw = &tc->mws[idx]; + struct tool_mw *outmw = &tc->outmws[widx]; - if (mw->peer) { - ntb_mw_clear_trans(tc->ntb, PIDX, idx); - dma_free_coherent(&tc->ntb->pdev->dev, mw->size, - mw->peer, - mw->peer_dma); - } + debugfs_remove(outmw->dbgfs_file); - mw->peer = NULL; - mw->peer_dma = 0; - - debugfs_remove(mw->peer_dbg_file); + if (outmw->io_base != NULL) { + iounmap(tc->outmws[widx].io_base); + ntb_peer_mw_clear_trans(tc->ntb, outmw->pidx, widx); + } - mw->peer_dbg_file = NULL; + outmw->io_base = NULL; + outmw->tr_base = 0; + outmw->size = 0; + outmw->pidx = -1; + outmw->dbgfs_file = NULL; } -static ssize_t tool_peer_mw_trans_read(struct file *filep, - char __user *ubuf, - size_t size, loff_t *offp) +static ssize_t tool_peer_mw_trans_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_mw *mw = filep->private_data; - - char *buf; + struct tool_mw_wrap *outmw_wrap = filep->private_data; + struct tool_mw *outmw = outmw_wrap->mw; + resource_size_t map_size; + phys_addr_t map_base; + ssize_t off = 0; size_t buf_size; - ssize_t ret, off = 0; + char *buf; + int ret; - phys_addr_t base; - resource_size_t mw_size; - resource_size_t align_addr = 0; - resource_size_t align_size = 0; - resource_size_t max_size = 0; + ret = ntb_peer_mw_get_addr(outmw->tc->ntb, outmw->widx, + &map_base, &map_size); + if (ret) + return ret; buf_size = min_t(size_t, size, 512); @@ -762,43 +888,37 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep, if (!buf) return -ENOMEM; - ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx, - &align_addr, &align_size, &max_size); - ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size); - off += scnprintf(buf + off, buf_size - off, - "Peer MW %d Information:\n", mw->idx); + "Outbound MW: \t%d\n", outmw->widx); - off += scnprintf(buf + off, buf_size - off, - "Physical Address \t%pa[p]\n", - &base); - - off += scnprintf(buf + off, buf_size - off, - "Window Size \t%lld\n", - (unsigned long long)mw_size); + if (outmw->io_base != NULL) { + off += scnprintf(buf + off, buf_size - off, + "Port attached \t%d (%d)\n", + ntb_peer_port_number(outmw->tc->ntb, outmw->pidx), + outmw->pidx); + } else { + off += scnprintf(buf + off, buf_size - off, + "Port attached \t-1 (-1)\n"); + } off += scnprintf(buf + off, buf_size - off, - "Alignment \t%lld\n", - (unsigned long long)align_addr); + "Virtual address \t0x%pK\n", outmw->io_base); off += scnprintf(buf + off, buf_size - off, - "Size Alignment \t%lld\n", - (unsigned long long)align_size); + "Phys Address \t%pa[p]\n", &map_base); off += scnprintf(buf + off, buf_size - off, - "Size Max \t%lld\n", - (unsigned long long)max_size); + "Mapping Size \t%pa[p]\n", &map_size); off += scnprintf(buf + off, buf_size - off, - "Ready \t%c\n", - (mw->peer) ? 'Y' : 'N'); + "Translation Address \t0x%016llx\n", outmw->tr_base); off += scnprintf(buf + off, buf_size - off, - "Allocated Size \t%zd\n", - (mw->peer) ? (size_t)mw->size : 0); + "Window Size \t%pa[p]\n", &outmw->size); ret = simple_read_from_buffer(ubuf, size, offp, buf, off); kfree(buf); + return ret; } @@ -806,12 +926,12 @@ static ssize_t tool_peer_mw_trans_write(struct file *filep, const char __user *ubuf, size_t size, loff_t *offp) { - struct tool_mw *mw = filep->private_data; - - char buf[32]; - size_t buf_size; - unsigned long long val; - int rc; + struct tool_mw_wrap *outmw_wrap = filep->private_data; + struct tool_mw *outmw = outmw_wrap->mw; + size_t buf_size, wsize; + char buf[TOOL_BUF_LEN]; + int ret, n; + u64 addr; buf_size = min(size, (sizeof(buf) - 1)); if (copy_from_user(buf, ubuf, buf_size)) @@ -819,16 +939,17 @@ static ssize_t tool_peer_mw_trans_write(struct file *filep, buf[buf_size] = '\0'; - rc = kstrtoull(buf, 0, &val); - if (rc) - return rc; - - tool_free_mw(mw->tc, mw->idx); - if (val) - rc = tool_setup_mw(mw->tc, mw->idx, val); + n = sscanf(buf, "%lli:%zi", &addr, &wsize); + if (n != 2) + return -EINVAL; - if (rc) - return rc; + tool_free_peer_mw(outmw->tc, outmw->widx); + if (wsize) { + ret = tool_setup_peer_mw(outmw->tc, outmw_wrap->pidx, + outmw->widx, addr, wsize); + if (ret) + return ret; + } return size; } @@ -837,195 +958,734 @@ static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops, tool_peer_mw_trans_read, tool_peer_mw_trans_write); -static int tool_init_mw(struct tool_ctx *tc, int idx) +static int tool_init_mws(struct tool_ctx *tc) { - struct tool_mw *mw = &tc->mws[idx]; - phys_addr_t base; - int rc; - - rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size); - if (rc) - return rc; - - mw->tc = tc; - mw->idx = idx; - mw->local = ioremap_wc(base, mw->win_size); - if (!mw->local) - return -EFAULT; + int widx, pidx; + + /* Initialize outbound memory windows */ + tc->outmw_cnt = ntb_peer_mw_count(tc->ntb); + tc->outmws = devm_kcalloc(&tc->ntb->dev, tc->outmw_cnt, + sizeof(*tc->outmws), GFP_KERNEL); + if (tc->outmws == NULL) + return -ENOMEM; + + for (widx = 0; widx < tc->outmw_cnt; widx++) { + tc->outmws[widx].widx = widx; + tc->outmws[widx].pidx = -1; + tc->outmws[widx].tc = tc; + } + + /* Initialize inbound memory windows and outbound MWs wrapper */ + for (pidx = 0; pidx < tc->peer_cnt; pidx++) { + tc->peers[pidx].inmw_cnt = ntb_mw_count(tc->ntb, pidx); + tc->peers[pidx].inmws = + devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].inmw_cnt, + sizeof(*tc->peers[pidx].inmws), GFP_KERNEL); + if (tc->peers[pidx].inmws == NULL) + return -ENOMEM; + + for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { + tc->peers[pidx].inmws[widx].widx = widx; + tc->peers[pidx].inmws[widx].pidx = pidx; + tc->peers[pidx].inmws[widx].tc = tc; + } + + tc->peers[pidx].outmw_cnt = ntb_peer_mw_count(tc->ntb); + tc->peers[pidx].outmws = + devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmw_cnt, + sizeof(*tc->peers[pidx].outmws), GFP_KERNEL); + + for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { + tc->peers[pidx].outmws[widx].pidx = pidx; + tc->peers[pidx].outmws[widx].mw = &tc->outmws[widx]; + } + } return 0; } -static void tool_free_mws(struct tool_ctx *tc) +static void tool_clear_mws(struct tool_ctx *tc) { - int i; + int widx, pidx; - for (i = 0; i < tc->mw_count; i++) { - tool_free_mw(tc, i); + /* Free outbound memory windows */ + for (widx = 0; widx < tc->outmw_cnt; widx++) + tool_free_peer_mw(tc, widx); - if (tc->mws[i].local) - iounmap(tc->mws[i].local); + /* Free outbound memory windows */ + for (pidx = 0; pidx < tc->peer_cnt; pidx++) + for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) + tool_free_mw(tc, pidx, widx); +} - tc->mws[i].local = NULL; - } +/*============================================================================== + * Doorbell read/write methods + *============================================================================== + */ + +static ssize_t tool_db_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read); } -static void tool_setup_dbgfs(struct tool_ctx *tc) +static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) { - int i; + struct tool_ctx *tc = filep->private_data; - /* This modules is useless without dbgfs... */ - if (!tool_dbgfs) { - tc->dbgfs = NULL; - return; + return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set, + tc->ntb->ops->db_clear); +} + +static TOOL_FOPS_RDWR(tool_db_fops, + tool_db_read, + tool_db_write); + +static ssize_t tool_db_valid_mask_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_valid_mask); +} + +static TOOL_FOPS_RDWR(tool_db_valid_mask_fops, + tool_db_valid_mask_read, + NULL); + +static ssize_t tool_db_mask_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->db_read_mask); +} + +static ssize_t tool_db_mask_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->db_set_mask, + tc->ntb->ops->db_clear_mask); +} + +static TOOL_FOPS_RDWR(tool_db_mask_fops, + tool_db_mask_read, + tool_db_mask_write); + +static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->peer_db_read); +} + +static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_write(tc, ubuf, size, offp, tc->ntb->ops->peer_db_set, + tc->ntb->ops->peer_db_clear); +} + +static TOOL_FOPS_RDWR(tool_peer_db_fops, + tool_peer_db_read, + tool_peer_db_write); + +static ssize_t tool_peer_db_mask_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, + tc->ntb->ops->peer_db_read_mask); +} + +static ssize_t tool_peer_db_mask_write(struct file *filep, + const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_write(tc, ubuf, size, offp, + tc->ntb->ops->peer_db_set_mask, + tc->ntb->ops->peer_db_clear_mask); +} + +static TOOL_FOPS_RDWR(tool_peer_db_mask_fops, + tool_peer_db_mask_read, + tool_peer_db_mask_write); + +static ssize_t tool_db_event_write(struct file *filep, + const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + u64 val; + int ret; + + ret = kstrtou64_from_user(ubuf, size, 0, &val); + if (ret) + return ret; + + if (wait_event_interruptible(tc->db_wq, ntb_db_read(tc->ntb) == val)) + return -ERESTART; + + return size; +} + +static TOOL_FOPS_RDWR(tool_db_event_fops, + NULL, + tool_db_event_write); + +/*============================================================================== + * Scratchpads read/write methods + *============================================================================== + */ + +static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_spad *spad = filep->private_data; + char buf[TOOL_BUF_LEN]; + ssize_t pos; + + if (!spad->tc->ntb->ops->spad_read) + return -EINVAL; + + pos = scnprintf(buf, sizeof(buf), "%#x\n", + ntb_spad_read(spad->tc->ntb, spad->sidx)); + + return simple_read_from_buffer(ubuf, size, offp, buf, pos); +} + +static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_spad *spad = filep->private_data; + u32 val; + int ret; + + if (!spad->tc->ntb->ops->spad_write) { + dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); + return -EINVAL; } - tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev), - tool_dbgfs); - if (!tc->dbgfs) - return; + ret = kstrtou32_from_user(ubuf, size, 0, &val); + if (ret) + return ret; - debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs, - tc, &tool_db_fops); + ret = ntb_spad_write(spad->tc->ntb, spad->sidx, val); - debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs, - tc, &tool_mask_fops); + return ret ?: size; +} - debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs, - tc, &tool_peer_db_fops); +static TOOL_FOPS_RDWR(tool_spad_fops, + tool_spad_read, + tool_spad_write); + +static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_spad *spad = filep->private_data; + char buf[TOOL_BUF_LEN]; + ssize_t pos; - debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs, - tc, &tool_peer_mask_fops); + if (!spad->tc->ntb->ops->peer_spad_read) + return -EINVAL; - debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs, - tc, &tool_spad_fops); + pos = scnprintf(buf, sizeof(buf), "%#x\n", + ntb_peer_spad_read(spad->tc->ntb, spad->pidx, spad->sidx)); - debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs, - tc, &tool_peer_spad_fops); + return simple_read_from_buffer(ubuf, size, offp, buf, pos); +} - debugfs_create_file("link", S_IRUSR | S_IWUSR, tc->dbgfs, - tc, &tool_link_fops); +static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_spad *spad = filep->private_data; + u32 val; + int ret; + + if (!spad->tc->ntb->ops->peer_spad_write) { + dev_dbg(&spad->tc->ntb->dev, "no spad write fn\n"); + return -EINVAL; + } + + ret = kstrtou32_from_user(ubuf, size, 0, &val); + if (ret) + return ret; - debugfs_create_file("link_event", S_IWUSR, tc->dbgfs, - tc, &tool_link_event_fops); + ret = ntb_peer_spad_write(spad->tc->ntb, spad->pidx, spad->sidx, val); - for (i = 0; i < tc->mw_count; i++) { - char buf[30]; + return ret ?: size; +} + +static TOOL_FOPS_RDWR(tool_peer_spad_fops, + tool_peer_spad_read, + tool_peer_spad_write); - snprintf(buf, sizeof(buf), "mw%d", i); - debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, - &tc->mws[i], &tool_mw_fops); +static int tool_init_spads(struct tool_ctx *tc) +{ + int sidx, pidx; - snprintf(buf, sizeof(buf), "peer_trans%d", i); - debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, - &tc->mws[i], &tool_peer_mw_trans_fops); + /* Initialize inbound scratchpad structures */ + tc->inspad_cnt = ntb_spad_count(tc->ntb); + tc->inspads = devm_kcalloc(&tc->ntb->dev, tc->inspad_cnt, + sizeof(*tc->inspads), GFP_KERNEL); + if (tc->inspads == NULL) + return -ENOMEM; + + for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { + tc->inspads[sidx].sidx = sidx; + tc->inspads[sidx].pidx = -1; + tc->inspads[sidx].tc = tc; } + + /* Initialize outbound scratchpad structures */ + for (pidx = 0; pidx < tc->peer_cnt; pidx++) { + tc->peers[pidx].outspad_cnt = ntb_spad_count(tc->ntb); + tc->peers[pidx].outspads = + devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outspad_cnt, + sizeof(*tc->peers[pidx].outspads), GFP_KERNEL); + if (tc->peers[pidx].outspads == NULL) + return -ENOMEM; + + for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { + tc->peers[pidx].outspads[sidx].sidx = sidx; + tc->peers[pidx].outspads[sidx].pidx = pidx; + tc->peers[pidx].outspads[sidx].tc = tc; + } + } + + return 0; } -static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) +/*============================================================================== + * Messages read/write methods + *============================================================================== + */ + +static ssize_t tool_inmsg_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) { - struct tool_ctx *tc; - int rc; - int i; + struct tool_msg *msg = filep->private_data; + char buf[TOOL_BUF_LEN]; + ssize_t pos; + u32 data; + int pidx; + + data = ntb_msg_read(msg->tc->ntb, &pidx, msg->midx); + + pos = scnprintf(buf, sizeof(buf), "0x%08x<-%d\n", data, pidx); + + return simple_read_from_buffer(ubuf, size, offp, buf, pos); +} + +static TOOL_FOPS_RDWR(tool_inmsg_fops, + tool_inmsg_read, + NULL); + +static ssize_t tool_outmsg_write(struct file *filep, + const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_msg *msg = filep->private_data; + u32 val; + int ret; + + ret = kstrtou32_from_user(ubuf, size, 0, &val); + if (ret) + return ret; + + ret = ntb_peer_msg_write(msg->tc->ntb, msg->pidx, msg->midx, val); + + return ret ? : size; +} + +static TOOL_FOPS_RDWR(tool_outmsg_fops, + NULL, + tool_outmsg_write); + +static ssize_t tool_msg_sts_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_read_sts); +} + +static ssize_t tool_msg_sts_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_write(tc, ubuf, size, offp, NULL, + tc->ntb->ops->msg_clear_sts); +} + +static TOOL_FOPS_RDWR(tool_msg_sts_fops, + tool_msg_sts_read, + tool_msg_sts_write); + +static ssize_t tool_msg_inbits_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_inbits); +} + +static TOOL_FOPS_RDWR(tool_msg_inbits_fops, + tool_msg_inbits_read, + NULL); + +static ssize_t tool_msg_outbits_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_read(tc, ubuf, size, offp, tc->ntb->ops->msg_outbits); +} + +static TOOL_FOPS_RDWR(tool_msg_outbits_fops, + tool_msg_outbits_read, + NULL); + +static ssize_t tool_msg_mask_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_fn_write(tc, ubuf, size, offp, + tc->ntb->ops->msg_set_mask, + tc->ntb->ops->msg_clear_mask); +} + +static TOOL_FOPS_RDWR(tool_msg_mask_fops, + NULL, + tool_msg_mask_write); + +static ssize_t tool_msg_event_write(struct file *filep, + const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + u64 val; + int ret; + + ret = kstrtou64_from_user(ubuf, size, 0, &val); + if (ret) + return ret; + + if (wait_event_interruptible(tc->msg_wq, + ntb_msg_read_sts(tc->ntb) == val)) + return -ERESTART; - if (!ntb->ops->mw_set_trans) { - dev_dbg(&ntb->dev, "need inbound MW based NTB API\n"); - rc = -EINVAL; - goto err_tc; + return size; +} + +static TOOL_FOPS_RDWR(tool_msg_event_fops, + NULL, + tool_msg_event_write); + +static int tool_init_msgs(struct tool_ctx *tc) +{ + int midx, pidx; + + /* Initialize inbound message structures */ + tc->inmsg_cnt = ntb_msg_count(tc->ntb); + tc->inmsgs = devm_kcalloc(&tc->ntb->dev, tc->inmsg_cnt, + sizeof(*tc->inmsgs), GFP_KERNEL); + if (tc->inmsgs == NULL) + return -ENOMEM; + + for (midx = 0; midx < tc->inmsg_cnt; midx++) { + tc->inmsgs[midx].midx = midx; + tc->inmsgs[midx].pidx = -1; + tc->inmsgs[midx].tc = tc; } - if (ntb_spad_count(ntb) < 1) { - dev_dbg(&ntb->dev, "no enough scratchpads\n"); - rc = -EINVAL; - goto err_tc; + /* Initialize outbound message structures */ + for (pidx = 0; pidx < tc->peer_cnt; pidx++) { + tc->peers[pidx].outmsg_cnt = ntb_msg_count(tc->ntb); + tc->peers[pidx].outmsgs = + devm_kcalloc(&tc->ntb->dev, tc->peers[pidx].outmsg_cnt, + sizeof(*tc->peers[pidx].outmsgs), GFP_KERNEL); + if (tc->peers[pidx].outmsgs == NULL) + return -ENOMEM; + + for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { + tc->peers[pidx].outmsgs[midx].midx = midx; + tc->peers[pidx].outmsgs[midx].pidx = pidx; + tc->peers[pidx].outmsgs[midx].tc = tc; + } } + return 0; +} + +/*============================================================================== + * Initialization methods + *============================================================================== + */ + +static struct tool_ctx *tool_create_data(struct ntb_dev *ntb) +{ + struct tool_ctx *tc; + + tc = devm_kzalloc(&ntb->dev, sizeof(*tc), GFP_KERNEL); + if (tc == NULL) + return ERR_PTR(-ENOMEM); + + tc->ntb = ntb; + init_waitqueue_head(&tc->link_wq); + init_waitqueue_head(&tc->db_wq); + init_waitqueue_head(&tc->msg_wq); + if (ntb_db_is_unsafe(ntb)) dev_dbg(&ntb->dev, "doorbell is unsafe\n"); if (ntb_spad_is_unsafe(ntb)) dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); - if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) - dev_warn(&ntb->dev, "multi-port NTB is unsupported\n"); + return tc; +} + +static void tool_clear_data(struct tool_ctx *tc) +{ + wake_up(&tc->link_wq); + wake_up(&tc->db_wq); + wake_up(&tc->msg_wq); +} + +static int tool_init_ntb(struct tool_ctx *tc) +{ + return ntb_set_ctx(tc->ntb, tc, &tool_ops); +} + +static void tool_clear_ntb(struct tool_ctx *tc) +{ + ntb_clear_ctx(tc->ntb); + ntb_link_disable(tc->ntb); +} - tc = kzalloc(sizeof(*tc), GFP_KERNEL); - if (!tc) { - rc = -ENOMEM; - goto err_tc; +static void tool_setup_dbgfs(struct tool_ctx *tc) +{ + int pidx, widx, sidx, midx; + char buf[TOOL_BUF_LEN]; + + /* This modules is useless without dbgfs... */ + if (!tool_dbgfs_topdir) { + tc->dbgfs_dir = NULL; + return; } - tc->ntb = ntb; - init_waitqueue_head(&tc->link_wq); + tc->dbgfs_dir = debugfs_create_dir(dev_name(&tc->ntb->dev), + tool_dbgfs_topdir); + if (!tc->dbgfs_dir) + return; + + debugfs_create_file("port", 0600, tc->dbgfs_dir, + tc, &tool_port_fops); + + debugfs_create_file("link", 0600, tc->dbgfs_dir, + tc, &tool_link_fops); + + debugfs_create_file("db", 0600, tc->dbgfs_dir, + tc, &tool_db_fops); + + debugfs_create_file("db_valid_mask", 0600, tc->dbgfs_dir, + tc, &tool_db_valid_mask_fops); + + debugfs_create_file("db_mask", 0600, tc->dbgfs_dir, + tc, &tool_db_mask_fops); + + debugfs_create_file("db_event", 0600, tc->dbgfs_dir, + tc, &tool_db_event_fops); - tc->mw_count = min(ntb_peer_mw_count(tc->ntb), MAX_MWS); - for (i = 0; i < tc->mw_count; i++) { - rc = tool_init_mw(tc, i); - if (rc) - goto err_ctx; + debugfs_create_file("peer_db", 0600, tc->dbgfs_dir, + tc, &tool_peer_db_fops); + + debugfs_create_file("peer_db_mask", 0600, tc->dbgfs_dir, + tc, &tool_peer_db_mask_fops); + + if (tc->inspad_cnt != 0) { + for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { + snprintf(buf, sizeof(buf), "spad%d", sidx); + + debugfs_create_file(buf, 0600, tc->dbgfs_dir, + &tc->inspads[sidx], &tool_spad_fops); + } } - tool_setup_dbgfs(tc); + if (tc->inmsg_cnt != 0) { + for (midx = 0; midx < tc->inmsg_cnt; midx++) { + snprintf(buf, sizeof(buf), "msg%d", midx); + debugfs_create_file(buf, 0600, tc->dbgfs_dir, + &tc->inmsgs[midx], &tool_inmsg_fops); + } + + debugfs_create_file("msg_sts", 0600, tc->dbgfs_dir, + tc, &tool_msg_sts_fops); + + debugfs_create_file("msg_inbits", 0600, tc->dbgfs_dir, + tc, &tool_msg_inbits_fops); + + debugfs_create_file("msg_outbits", 0600, tc->dbgfs_dir, + tc, &tool_msg_outbits_fops); + + debugfs_create_file("msg_mask", 0600, tc->dbgfs_dir, + tc, &tool_msg_mask_fops); + + debugfs_create_file("msg_event", 0600, tc->dbgfs_dir, + tc, &tool_msg_event_fops); + } + + for (pidx = 0; pidx < tc->peer_cnt; pidx++) { + snprintf(buf, sizeof(buf), "peer%d", pidx); + tc->peers[pidx].dbgfs_dir = + debugfs_create_dir(buf, tc->dbgfs_dir); + + debugfs_create_file("port", 0600, + tc->peers[pidx].dbgfs_dir, + &tc->peers[pidx], &tool_peer_port_fops); + + debugfs_create_file("link", 0200, + tc->peers[pidx].dbgfs_dir, + &tc->peers[pidx], &tool_peer_link_fops); + + debugfs_create_file("link_event", 0200, + tc->peers[pidx].dbgfs_dir, + &tc->peers[pidx], &tool_peer_link_event_fops); + + for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { + snprintf(buf, sizeof(buf), "mw_trans%d", widx); + debugfs_create_file(buf, 0600, + tc->peers[pidx].dbgfs_dir, + &tc->peers[pidx].inmws[widx], + &tool_mw_trans_fops); + } + + for (widx = 0; widx < tc->peers[pidx].outmw_cnt; widx++) { + snprintf(buf, sizeof(buf), "peer_mw_trans%d", widx); + debugfs_create_file(buf, 0600, + tc->peers[pidx].dbgfs_dir, + &tc->peers[pidx].outmws[widx], + &tool_peer_mw_trans_fops); + } + + for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { + snprintf(buf, sizeof(buf), "spad%d", sidx); + + debugfs_create_file(buf, 0600, + tc->peers[pidx].dbgfs_dir, + &tc->peers[pidx].outspads[sidx], + &tool_peer_spad_fops); + } + + for (midx = 0; midx < tc->peers[pidx].outmsg_cnt; midx++) { + snprintf(buf, sizeof(buf), "msg%d", midx); + debugfs_create_file(buf, 0600, + tc->peers[pidx].dbgfs_dir, + &tc->peers[pidx].outmsgs[midx], + &tool_outmsg_fops); + } + } +} + +static void tool_clear_dbgfs(struct tool_ctx *tc) +{ + debugfs_remove_recursive(tc->dbgfs_dir); +} + +static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) +{ + struct tool_ctx *tc; + int ret; - rc = ntb_set_ctx(ntb, tc, &tool_ops); - if (rc) - goto err_ctx; + tc = tool_create_data(ntb); + if (IS_ERR(tc)) + return PTR_ERR(tc); - ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); - ntb_link_event(ntb); + ret = tool_init_peers(tc); + if (ret != 0) + goto err_clear_data; + + ret = tool_init_mws(tc); + if (ret != 0) + goto err_clear_data; + + ret = tool_init_spads(tc); + if (ret != 0) + goto err_clear_mws; + + ret = tool_init_msgs(tc); + if (ret != 0) + goto err_clear_mws; + + ret = tool_init_ntb(tc); + if (ret != 0) + goto err_clear_mws; + + tool_setup_dbgfs(tc); return 0; -err_ctx: - tool_free_mws(tc); - debugfs_remove_recursive(tc->dbgfs); - kfree(tc); -err_tc: - return rc; +err_clear_mws: + tool_clear_mws(tc); + +err_clear_data: + tool_clear_data(tc); + + return ret; } static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) { struct tool_ctx *tc = ntb->ctx; - tool_free_mws(tc); + tool_clear_dbgfs(tc); + + tool_clear_ntb(tc); - ntb_clear_ctx(ntb); - ntb_link_disable(ntb); + tool_clear_mws(tc); - debugfs_remove_recursive(tc->dbgfs); - kfree(tc); + tool_clear_data(tc); } static struct ntb_client tool_client = { .ops = { .probe = tool_probe, .remove = tool_remove, - }, + } }; static int __init tool_init(void) { - int rc; + int ret; if (debugfs_initialized()) - tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL); - - rc = ntb_register_client(&tool_client); - if (rc) - goto err_client; + tool_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); - return 0; + ret = ntb_register_client(&tool_client); + if (ret) + debugfs_remove_recursive(tool_dbgfs_topdir); -err_client: - debugfs_remove_recursive(tool_dbgfs); - return rc; + return ret; } module_init(tool_init); static void __exit tool_exit(void) { ntb_unregister_client(&tool_client); - debugfs_remove_recursive(tool_dbgfs); + debugfs_remove_recursive(tool_dbgfs_topdir); } module_exit(tool_exit); + -- cgit From 5648e56d03fa0c153fccd089efd903f1f6af559f Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 6 Dec 2017 17:31:57 +0300 Subject: NTB: ntb_perf: Add full multi-port NTB API support Former NTB Performance driver could only work with NTB devices, which got Scratchpads available and had just two ports. Since there are devices, which don't have Scratchpads and got more than two peer ports, the performance measuring tool needs to be rewritten. This patch adds the ability to test any available NTB peer. Additionally it allows to set NTB memory windows up using any available data exchange interface: Scratchpad or Message registers. Some cleanups are also added here. Signed-off-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/test/ntb_perf.c | 1820 +++++++++++++++++++++++++++++-------------- 1 file changed, 1219 insertions(+), 601 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c index 6f6c602d04af..8de72f3fba4d 100644 --- a/drivers/ntb/test/ntb_perf.c +++ b/drivers/ntb/test/ntb_perf.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2017 T-Platforms. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2017 T-Platforms. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,859 +42,1475 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * PCIe NTB Perf Linux driver + * PCIe NTB Perf Linux driver + */ + +/* + * How to use this tool, by example. + * + * Assuming $DBG_DIR is something like: + * '/sys/kernel/debug/ntb_perf/0000:00:03.0' + * Suppose aside from local device there is at least one remote device + * connected to NTB with index 0. + *----------------------------------------------------------------------------- + * Eg: install driver with specified chunk/total orders and dma-enabled flag + * + * root@self# insmod ntb_perf.ko chunk_order=19 total_order=28 use_dma + *----------------------------------------------------------------------------- + * Eg: check NTB ports (index) and MW mapping information + * + * root@self# cat $DBG_DIR/info + *----------------------------------------------------------------------------- + * Eg: start performance test with peer (index 0) and get the test metrics + * + * root@self# echo 0 > $DBG_DIR/run + * root@self# cat $DBG_DIR/run */ #include #include #include -#include -#include -#include +#include +#include #include +#include #include +#include #include -#include -#include -#include #include #include +#include +#include +#include #include -#include #define DRIVER_NAME "ntb_perf" -#define DRIVER_DESCRIPTION "PCIe NTB Performance Measurement Tool" - -#define DRIVER_VERSION "1.0" -#define DRIVER_AUTHOR "Dave Jiang " - -#define PERF_LINK_DOWN_TIMEOUT 10 -#define PERF_VERSION 0xffff0001 -#define MAX_THREADS 32 -#define MAX_TEST_SIZE SZ_1M -#define MAX_SRCS 32 -#define DMA_OUT_RESOURCE_TO msecs_to_jiffies(50) -#define DMA_RETRIES 20 -#define SZ_4G (1ULL << 32) -#define MAX_SEG_ORDER 20 /* no larger than 1M for kmalloc buffer */ -#define PIDX NTB_DEF_PEER_IDX +#define DRIVER_VERSION "2.0" MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESCRIPTION); +MODULE_AUTHOR("Dave Jiang "); +MODULE_DESCRIPTION("PCIe NTB Performance Measurement Tool"); + +#define MAX_THREADS_CNT 32 +#define DEF_THREADS_CNT 1 +#define MAX_CHUNK_SIZE SZ_1M +#define MAX_CHUNK_ORDER 20 /* no larger than 1M */ + +#define DMA_TRIES 100 +#define DMA_MDELAY 10 -static struct dentry *perf_debugfs_dir; +#define MSG_TRIES 500 +#define MSG_UDELAY_LOW 1000 +#define MSG_UDELAY_HIGH 2000 + +#define PERF_BUF_LEN 1024 static unsigned long max_mw_size; module_param(max_mw_size, ulong, 0644); -MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows"); +MODULE_PARM_DESC(max_mw_size, "Upper limit of memory window size"); -static unsigned int seg_order = 19; /* 512K */ -module_param(seg_order, uint, 0644); -MODULE_PARM_DESC(seg_order, "size order [2^n] of buffer segment for testing"); +static unsigned char chunk_order = 19; /* 512K */ +module_param(chunk_order, byte, 0644); +MODULE_PARM_DESC(chunk_order, "Data chunk order [2^n] to transfer"); -static unsigned int run_order = 32; /* 4G */ -module_param(run_order, uint, 0644); -MODULE_PARM_DESC(run_order, "size order [2^n] of total data to transfer"); +static unsigned char total_order = 30; /* 1G */ +module_param(total_order, byte, 0644); +MODULE_PARM_DESC(total_order, "Total data order [2^n] to transfer"); static bool use_dma; /* default to 0 */ module_param(use_dma, bool, 0644); -MODULE_PARM_DESC(use_dma, "Using DMA engine to measure performance"); - -static bool on_node = true; /* default to 1 */ -module_param(on_node, bool, 0644); -MODULE_PARM_DESC(on_node, "Run threads only on NTB device node (default: true)"); - -struct perf_mw { - phys_addr_t phys_addr; - resource_size_t phys_size; - void __iomem *vbase; - size_t xlat_size; - size_t buf_size; - void *virt_addr; - dma_addr_t dma_addr; +MODULE_PARM_DESC(use_dma, "Use DMA engine to measure performance"); + +/*============================================================================== + * Perf driver data definition + *============================================================================== + */ + +enum perf_cmd { + PERF_CMD_INVAL = -1,/* invalid spad command */ + PERF_CMD_SSIZE = 0, /* send out buffer size */ + PERF_CMD_RSIZE = 1, /* recv in buffer size */ + PERF_CMD_SXLAT = 2, /* send in buffer xlat */ + PERF_CMD_RXLAT = 3, /* recv out buffer xlat */ + PERF_CMD_CLEAR = 4, /* clear allocated memory */ + PERF_STS_DONE = 5, /* init is done */ + PERF_STS_LNKUP = 6, /* link up state flag */ }; struct perf_ctx; -struct pthr_ctx { - struct task_struct *thread; - struct perf_ctx *perf; - atomic_t dma_sync; - struct dma_chan *dma_chan; - int dma_prep_err; - int src_idx; - void *srcs[MAX_SRCS]; - wait_queue_head_t *wq; - int status; - u64 copied; - u64 diff_us; +struct perf_peer { + struct perf_ctx *perf; + int pidx; + int gidx; + + /* Outbound MW params */ + u64 outbuf_xlat; + resource_size_t outbuf_size; + void __iomem *outbuf; + + /* Inbound MW params */ + dma_addr_t inbuf_xlat; + resource_size_t inbuf_size; + void *inbuf; + + /* NTB connection setup service */ + struct work_struct service; + unsigned long sts; }; +#define to_peer_service(__work) \ + container_of(__work, struct perf_peer, service) -struct perf_ctx { - struct ntb_dev *ntb; - spinlock_t db_lock; - struct perf_mw mw; - bool link_is_up; - struct delayed_work link_work; - wait_queue_head_t link_wq; - u8 perf_threads; - /* mutex ensures only one set of threads run at once */ - struct mutex run_mutex; - struct pthr_ctx pthr_ctx[MAX_THREADS]; - atomic_t tsync; - atomic_t tdone; +struct perf_thread { + struct perf_ctx *perf; + int tidx; + + /* DMA-based test sync parameters */ + atomic_t dma_sync; + wait_queue_head_t dma_wait; + struct dma_chan *dma_chan; + + /* Data source and measured statistics */ + void *src; + u64 copied; + ktime_t duration; + int status; + struct work_struct work; }; +#define to_thread_work(__work) \ + container_of(__work, struct perf_thread, work) -enum { - VERSION = 0, - MW_SZ_HIGH, - MW_SZ_LOW, - MAX_SPAD +struct perf_ctx { + struct ntb_dev *ntb; + + /* Global device index and peers descriptors */ + int gidx; + int pcnt; + struct perf_peer *peers; + + /* Performance measuring work-threads interface */ + unsigned long busy_flag; + wait_queue_head_t twait; + atomic_t tsync; + u8 tcnt; + struct perf_peer *test_peer; + struct perf_thread threads[MAX_THREADS_CNT]; + + /* Scratchpad/Message IO operations */ + int (*cmd_send)(struct perf_peer *peer, enum perf_cmd cmd, u64 data); + int (*cmd_recv)(struct perf_ctx *perf, int *pidx, enum perf_cmd *cmd, + u64 *data); + + struct dentry *dbgfs_dir; }; +/* + * Scratchpads-base commands interface + */ +#define PERF_SPAD_CNT(_pcnt) \ + (3*((_pcnt) + 1)) +#define PERF_SPAD_CMD(_gidx) \ + (3*(_gidx)) +#define PERF_SPAD_LDATA(_gidx) \ + (3*(_gidx) + 1) +#define PERF_SPAD_HDATA(_gidx) \ + (3*(_gidx) + 2) +#define PERF_SPAD_NOTIFY(_gidx) \ + (BIT_ULL(_gidx)) + +/* + * Messages-base commands interface + */ +#define PERF_MSG_CNT 3 +#define PERF_MSG_CMD 0 +#define PERF_MSG_LDATA 1 +#define PERF_MSG_HDATA 2 + +/*============================================================================== + * Static data declarations + *============================================================================== + */ + +static struct dentry *perf_dbgfs_topdir; + +static struct workqueue_struct *perf_wq __read_mostly; + +/*============================================================================== + * NTB cross-link commands execution service + *============================================================================== + */ + +static void perf_terminate_test(struct perf_ctx *perf); + +static inline bool perf_link_is_up(struct perf_peer *peer) +{ + u64 link; + + link = ntb_link_is_up(peer->perf->ntb, NULL, NULL); + return !!(link & BIT_ULL_MASK(peer->pidx)); +} + +static int perf_spad_cmd_send(struct perf_peer *peer, enum perf_cmd cmd, + u64 data) +{ + struct perf_ctx *perf = peer->perf; + int try; + u32 sts; + + dev_dbg(&perf->ntb->dev, "CMD send: %d 0x%llx\n", cmd, data); + + /* + * Perform predefined number of attempts before give up. + * We are sending the data to the port specific scratchpad, so + * to prevent a multi-port access race-condition. Additionally + * there is no need in local locking since only thread-safe + * service work is using this method. + */ + for (try = 0; try < MSG_TRIES; try++) { + if (!perf_link_is_up(peer)) + return -ENOLINK; + + sts = ntb_peer_spad_read(perf->ntb, peer->pidx, + PERF_SPAD_CMD(perf->gidx)); + if (le32_to_cpu(sts) != PERF_CMD_INVAL) { + usleep_range(MSG_UDELAY_LOW, MSG_UDELAY_HIGH); + continue; + } + + ntb_peer_spad_write(perf->ntb, peer->pidx, + PERF_SPAD_LDATA(perf->gidx), + cpu_to_le32(lower_32_bits(data))); + ntb_peer_spad_write(perf->ntb, peer->pidx, + PERF_SPAD_HDATA(perf->gidx), + cpu_to_le32(upper_32_bits(data))); + mmiowb(); + ntb_peer_spad_write(perf->ntb, peer->pidx, + PERF_SPAD_CMD(perf->gidx), + cpu_to_le32(cmd)); + mmiowb(); + ntb_peer_db_set(perf->ntb, PERF_SPAD_NOTIFY(peer->gidx)); + + dev_dbg(&perf->ntb->dev, "DB ring peer %#llx\n", + PERF_SPAD_NOTIFY(peer->gidx)); + + break; + } + + return try < MSG_TRIES ? 0 : -EAGAIN; +} + +static int perf_spad_cmd_recv(struct perf_ctx *perf, int *pidx, + enum perf_cmd *cmd, u64 *data) +{ + struct perf_peer *peer; + u32 val; + + ntb_db_clear(perf->ntb, PERF_SPAD_NOTIFY(perf->gidx)); + + /* + * We start scanning all over, since cleared DB may have been set + * by any peer. Yes, it makes peer with smaller index being + * serviced with greater priority, but it's convenient for spad + * and message code unification and simplicity. + */ + for (*pidx = 0; *pidx < perf->pcnt; (*pidx)++) { + peer = &perf->peers[*pidx]; + + if (!perf_link_is_up(peer)) + continue; + + val = ntb_spad_read(perf->ntb, PERF_SPAD_CMD(peer->gidx)); + val = le32_to_cpu(val); + if (val == PERF_CMD_INVAL) + continue; + + *cmd = val; + + val = ntb_spad_read(perf->ntb, PERF_SPAD_LDATA(peer->gidx)); + *data = le32_to_cpu(val); + + val = ntb_spad_read(perf->ntb, PERF_SPAD_HDATA(peer->gidx)); + *data |= (u64)le32_to_cpu(val) << 32; + + /* Next command can be retrieved from now */ + ntb_spad_write(perf->ntb, PERF_SPAD_CMD(peer->gidx), + cpu_to_le32(PERF_CMD_INVAL)); + + dev_dbg(&perf->ntb->dev, "CMD recv: %d 0x%llx\n", *cmd, *data); + + return 0; + } + + return -ENODATA; +} + +static int perf_msg_cmd_send(struct perf_peer *peer, enum perf_cmd cmd, + u64 data) +{ + struct perf_ctx *perf = peer->perf; + int try, ret; + u64 outbits; + + dev_dbg(&perf->ntb->dev, "CMD send: %d 0x%llx\n", cmd, data); + + /* + * Perform predefined number of attempts before give up. Message + * registers are free of race-condition problem when accessed + * from different ports, so we don't need splitting registers + * by global device index. We also won't have local locking, + * since the method is used from service work only. + */ + outbits = ntb_msg_outbits(perf->ntb); + for (try = 0; try < MSG_TRIES; try++) { + if (!perf_link_is_up(peer)) + return -ENOLINK; + + ret = ntb_msg_clear_sts(perf->ntb, outbits); + if (ret) + return ret; + + ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_LDATA, + cpu_to_le32(lower_32_bits(data))); + + if (ntb_msg_read_sts(perf->ntb) & outbits) { + usleep_range(MSG_UDELAY_LOW, MSG_UDELAY_HIGH); + continue; + } + + ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_HDATA, + cpu_to_le32(upper_32_bits(data))); + mmiowb(); + + /* This call shall trigger peer message event */ + ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_CMD, + cpu_to_le32(cmd)); + + break; + } + + return try < MSG_TRIES ? 0 : -EAGAIN; +} + +static int perf_msg_cmd_recv(struct perf_ctx *perf, int *pidx, + enum perf_cmd *cmd, u64 *data) +{ + u64 inbits; + u32 val; + + inbits = ntb_msg_inbits(perf->ntb); + + if (hweight64(ntb_msg_read_sts(perf->ntb) & inbits) < 3) + return -ENODATA; + + val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_CMD); + *cmd = le32_to_cpu(val); + + val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_LDATA); + *data = le32_to_cpu(val); + + val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_HDATA); + *data |= (u64)le32_to_cpu(val) << 32; + + /* Next command can be retrieved from now */ + ntb_msg_clear_sts(perf->ntb, inbits); + + dev_dbg(&perf->ntb->dev, "CMD recv: %d 0x%llx\n", *cmd, *data); + + return 0; +} + +static int perf_cmd_send(struct perf_peer *peer, enum perf_cmd cmd, u64 data) +{ + struct perf_ctx *perf = peer->perf; + + if (cmd == PERF_CMD_SSIZE || cmd == PERF_CMD_SXLAT) + return perf->cmd_send(peer, cmd, data); + + dev_err(&perf->ntb->dev, "Send invalid command\n"); + return -EINVAL; +} + +static int perf_cmd_exec(struct perf_peer *peer, enum perf_cmd cmd) +{ + switch (cmd) { + case PERF_CMD_SSIZE: + case PERF_CMD_RSIZE: + case PERF_CMD_SXLAT: + case PERF_CMD_RXLAT: + case PERF_CMD_CLEAR: + break; + default: + dev_err(&peer->perf->ntb->dev, "Exec invalid command\n"); + return -EINVAL; + } + + /* No need of memory barrier, since bit ops have invernal lock */ + set_bit(cmd, &peer->sts); + + dev_dbg(&peer->perf->ntb->dev, "CMD exec: %d\n", cmd); + + (void)queue_work(system_highpri_wq, &peer->service); + + return 0; +} + +static int perf_cmd_recv(struct perf_ctx *perf) +{ + struct perf_peer *peer; + int ret, pidx, cmd; + u64 data; + + while (!(ret = perf->cmd_recv(perf, &pidx, &cmd, &data))) { + peer = &perf->peers[pidx]; + + switch (cmd) { + case PERF_CMD_SSIZE: + peer->inbuf_size = data; + return perf_cmd_exec(peer, PERF_CMD_RSIZE); + case PERF_CMD_SXLAT: + peer->outbuf_xlat = data; + return perf_cmd_exec(peer, PERF_CMD_RXLAT); + default: + dev_err(&perf->ntb->dev, "Recv invalid command\n"); + return -EINVAL; + } + } + + /* Return 0 if no data left to process, otherwise an error */ + return ret == -ENODATA ? 0 : ret; +} + static void perf_link_event(void *ctx) { struct perf_ctx *perf = ctx; + struct perf_peer *peer; + bool lnk_up; + int pidx; - if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) { - schedule_delayed_work(&perf->link_work, 2*HZ); - } else { - dev_dbg(&perf->ntb->pdev->dev, "link down\n"); + for (pidx = 0; pidx < perf->pcnt; pidx++) { + peer = &perf->peers[pidx]; - if (!perf->link_is_up) - cancel_delayed_work_sync(&perf->link_work); + lnk_up = perf_link_is_up(peer); - perf->link_is_up = false; + if (lnk_up && + !test_and_set_bit(PERF_STS_LNKUP, &peer->sts)) { + perf_cmd_exec(peer, PERF_CMD_SSIZE); + } else if (!lnk_up && + test_and_clear_bit(PERF_STS_LNKUP, &peer->sts)) { + perf_cmd_exec(peer, PERF_CMD_CLEAR); + } } } static void perf_db_event(void *ctx, int vec) { struct perf_ctx *perf = ctx; - u64 db_bits, db_mask; - db_mask = ntb_db_vector_mask(perf->ntb, vec); - db_bits = ntb_db_read(perf->ntb); + dev_dbg(&perf->ntb->dev, "DB vec %d mask %#llx bits %#llx\n", vec, + ntb_db_vector_mask(perf->ntb, vec), ntb_db_read(perf->ntb)); + + /* Just receive all available commands */ + (void)perf_cmd_recv(perf); +} + +static void perf_msg_event(void *ctx) +{ + struct perf_ctx *perf = ctx; + + dev_dbg(&perf->ntb->dev, "Msg status bits %#llx\n", + ntb_msg_read_sts(perf->ntb)); - dev_dbg(&perf->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", - vec, db_mask, db_bits); + /* Messages are only sent one-by-one */ + (void)perf_cmd_recv(perf); } static const struct ntb_ctx_ops perf_ops = { .link_event = perf_link_event, .db_event = perf_db_event, + .msg_event = perf_msg_event }; -static void perf_copy_callback(void *data) +static void perf_free_outbuf(struct perf_peer *peer) +{ + (void)ntb_peer_mw_clear_trans(peer->perf->ntb, peer->pidx, peer->gidx); +} + +static int perf_setup_outbuf(struct perf_peer *peer) { - struct pthr_ctx *pctx = data; + struct perf_ctx *perf = peer->perf; + int ret; + + /* Outbuf size can be unaligned due to custom max_mw_size */ + ret = ntb_peer_mw_set_trans(perf->ntb, peer->pidx, peer->gidx, + peer->outbuf_xlat, peer->outbuf_size); + if (ret) { + dev_err(&perf->ntb->dev, "Failed to set outbuf translation\n"); + return ret; + } + + /* Initialization is finally done */ + set_bit(PERF_STS_DONE, &peer->sts); - atomic_dec(&pctx->dma_sync); + return 0; } -static ssize_t perf_copy(struct pthr_ctx *pctx, char __iomem *dst, - char *src, size_t size) +static void perf_free_inbuf(struct perf_peer *peer) { - struct perf_ctx *perf = pctx->perf; - struct dma_async_tx_descriptor *txd; - struct dma_chan *chan = pctx->dma_chan; - struct dma_device *device; - struct dmaengine_unmap_data *unmap; - dma_cookie_t cookie; - size_t src_off, dst_off; - struct perf_mw *mw = &perf->mw; - void __iomem *vbase; - void __iomem *dst_vaddr; - dma_addr_t dst_phys; - int retries = 0; + if (!peer->inbuf) + return; - if (!use_dma) { - memcpy_toio(dst, src, size); - return size; + (void)ntb_mw_clear_trans(peer->perf->ntb, peer->pidx, peer->gidx); + dma_free_coherent(&peer->perf->ntb->dev, peer->inbuf_size, + peer->inbuf, peer->inbuf_xlat); + peer->inbuf = NULL; +} + +static int perf_setup_inbuf(struct perf_peer *peer) +{ + resource_size_t xlat_align, size_align, size_max; + struct perf_ctx *perf = peer->perf; + int ret; + + /* Get inbound MW parameters */ + ret = ntb_mw_get_align(perf->ntb, peer->pidx, perf->gidx, + &xlat_align, &size_align, &size_max); + if (ret) { + dev_err(&perf->ntb->dev, "Couldn't get inbuf restrictions\n"); + return ret; } - if (!chan) { - dev_err(&perf->ntb->dev, "DMA engine does not exist\n"); + if (peer->inbuf_size > size_max) { + dev_err(&perf->ntb->dev, "Too big inbuf size %pa > %pa\n", + &peer->inbuf_size, &size_max); return -EINVAL; } - device = chan->device; - src_off = (uintptr_t)src & ~PAGE_MASK; - dst_off = (uintptr_t __force)dst & ~PAGE_MASK; + peer->inbuf_size = round_up(peer->inbuf_size, size_align); - if (!is_dma_copy_aligned(device, src_off, dst_off, size)) - return -ENODEV; - - vbase = mw->vbase; - dst_vaddr = dst; - dst_phys = mw->phys_addr + (dst_vaddr - vbase); + perf_free_inbuf(peer); - unmap = dmaengine_get_unmap_data(device->dev, 1, GFP_NOWAIT); - if (!unmap) + peer->inbuf = dma_alloc_coherent(&perf->ntb->dev, peer->inbuf_size, + &peer->inbuf_xlat, GFP_KERNEL); + if (!peer->inbuf) { + dev_err(&perf->ntb->dev, "Failed to alloc inbuf of %pa\n", + &peer->inbuf_size); return -ENOMEM; + } + if (!IS_ALIGNED(peer->inbuf_xlat, xlat_align)) { + dev_err(&perf->ntb->dev, "Unaligned inbuf allocated\n"); + goto err_free_inbuf; + } - unmap->len = size; - unmap->addr[0] = dma_map_page(device->dev, virt_to_page(src), - src_off, size, DMA_TO_DEVICE); - if (dma_mapping_error(device->dev, unmap->addr[0])) - goto err_get_unmap; + ret = ntb_mw_set_trans(perf->ntb, peer->pidx, peer->gidx, + peer->inbuf_xlat, peer->inbuf_size); + if (ret) { + dev_err(&perf->ntb->dev, "Failed to set inbuf translation\n"); + goto err_free_inbuf; + } - unmap->to_cnt = 1; + /* + * We submit inbuf xlat transmission cmd for execution here to follow + * the code architecture, even though this method is called from service + * work itself so the command will be executed right after it returns. + */ + (void)perf_cmd_exec(peer, PERF_CMD_SXLAT); - do { - txd = device->device_prep_dma_memcpy(chan, dst_phys, - unmap->addr[0], - size, DMA_PREP_INTERRUPT); - if (!txd) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(DMA_OUT_RESOURCE_TO); - } - } while (!txd && (++retries < DMA_RETRIES)); + return 0; - if (!txd) { - pctx->dma_prep_err++; - goto err_get_unmap; - } +err_free_inbuf: + perf_free_inbuf(peer); - txd->callback = perf_copy_callback; - txd->callback_param = pctx; - dma_set_unmap(txd, unmap); + return ret; +} - cookie = dmaengine_submit(txd); - if (dma_submit_error(cookie)) - goto err_set_unmap; +static void perf_service_work(struct work_struct *work) +{ + struct perf_peer *peer = to_peer_service(work); - dmaengine_unmap_put(unmap); + if (test_and_clear_bit(PERF_CMD_SSIZE, &peer->sts)) + perf_cmd_send(peer, PERF_CMD_SSIZE, peer->outbuf_size); - atomic_inc(&pctx->dma_sync); - dma_async_issue_pending(chan); + if (test_and_clear_bit(PERF_CMD_RSIZE, &peer->sts)) + perf_setup_inbuf(peer); - return size; + if (test_and_clear_bit(PERF_CMD_SXLAT, &peer->sts)) + perf_cmd_send(peer, PERF_CMD_SXLAT, peer->inbuf_xlat); -err_set_unmap: - dmaengine_unmap_put(unmap); -err_get_unmap: - dmaengine_unmap_put(unmap); - return 0; -} + if (test_and_clear_bit(PERF_CMD_RXLAT, &peer->sts)) + perf_setup_outbuf(peer); -static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src, - u64 buf_size, u64 win_size, u64 total) -{ - int chunks, total_chunks, i; - int copied_chunks = 0; - u64 copied = 0, result; - char __iomem *tmp = dst; - u64 perf, diff_us; - ktime_t kstart, kstop, kdiff; - unsigned long last_sleep = jiffies; - - chunks = div64_u64(win_size, buf_size); - total_chunks = div64_u64(total, buf_size); - kstart = ktime_get(); - - for (i = 0; i < total_chunks; i++) { - result = perf_copy(pctx, tmp, src, buf_size); - copied += result; - copied_chunks++; - if (copied_chunks == chunks) { - tmp = dst; - copied_chunks = 0; - } else - tmp += buf_size; - - /* Probably should schedule every 5s to prevent soft hang. */ - if (unlikely((jiffies - last_sleep) > 5 * HZ)) { - last_sleep = jiffies; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + if (test_and_clear_bit(PERF_CMD_CLEAR, &peer->sts)) { + clear_bit(PERF_STS_DONE, &peer->sts); + if (test_bit(0, &peer->perf->busy_flag) && + peer == peer->perf->test_peer) { + dev_warn(&peer->perf->ntb->dev, + "Freeing while test on-fly\n"); + perf_terminate_test(peer->perf); } + perf_free_outbuf(peer); + perf_free_inbuf(peer); + } +} - if (unlikely(kthread_should_stop())) - break; +static int perf_init_service(struct perf_ctx *perf) +{ + u64 mask; + + if (ntb_peer_mw_count(perf->ntb) < perf->pcnt + 1) { + dev_err(&perf->ntb->dev, "Not enough memory windows\n"); + return -EINVAL; } - if (use_dma) { - pr_debug("%s: All DMA descriptors submitted\n", current->comm); - while (atomic_read(&pctx->dma_sync) != 0) { - if (kthread_should_stop()) - break; - msleep(20); - } + if (ntb_msg_count(perf->ntb) >= PERF_MSG_CNT) { + perf->cmd_send = perf_msg_cmd_send; + perf->cmd_recv = perf_msg_cmd_recv; + + dev_dbg(&perf->ntb->dev, "Message service initialized\n"); + + return 0; } - kstop = ktime_get(); - kdiff = ktime_sub(kstop, kstart); - diff_us = ktime_to_us(kdiff); + dev_dbg(&perf->ntb->dev, "Message service unsupported\n"); - pr_debug("%s: copied %llu bytes\n", current->comm, copied); + mask = GENMASK_ULL(perf->pcnt, 0); + if (ntb_spad_count(perf->ntb) >= PERF_SPAD_CNT(perf->pcnt) && + (ntb_db_valid_mask(perf->ntb) & mask) == mask) { + perf->cmd_send = perf_spad_cmd_send; + perf->cmd_recv = perf_spad_cmd_recv; - pr_debug("%s: lasted %llu usecs\n", current->comm, diff_us); + dev_dbg(&perf->ntb->dev, "Scratchpad service initialized\n"); - perf = div64_u64(copied, diff_us); + return 0; + } - pr_debug("%s: MBytes/s: %llu\n", current->comm, perf); + dev_dbg(&perf->ntb->dev, "Scratchpad service unsupported\n"); - pctx->copied = copied; - pctx->diff_us = diff_us; + dev_err(&perf->ntb->dev, "Command services unsupported\n"); - return 0; + return -EINVAL; } -static bool perf_dma_filter_fn(struct dma_chan *chan, void *node) +static int perf_enable_service(struct perf_ctx *perf) { - /* Is the channel required to be on the same node as the device? */ - if (!on_node) - return true; + u64 mask, incmd_bit; + int ret, sidx, scnt; - return dev_to_node(&chan->dev->device) == (int)(unsigned long)node; -} + mask = ntb_db_valid_mask(perf->ntb); + (void)ntb_db_set_mask(perf->ntb, mask); -static int ntb_perf_thread(void *data) -{ - struct pthr_ctx *pctx = data; - struct perf_ctx *perf = pctx->perf; - struct pci_dev *pdev = perf->ntb->pdev; - struct perf_mw *mw = &perf->mw; - char __iomem *dst; - u64 win_size, buf_size, total; - void *src; - int rc, node, i; - struct dma_chan *dma_chan = NULL; + ret = ntb_set_ctx(perf->ntb, perf, &perf_ops); + if (ret) + return ret; - pr_debug("kthread %s starting...\n", current->comm); + if (perf->cmd_send == perf_msg_cmd_send) { + u64 inbits, outbits; - node = on_node ? dev_to_node(&pdev->dev) : NUMA_NO_NODE; + inbits = ntb_msg_inbits(perf->ntb); + outbits = ntb_msg_outbits(perf->ntb); + (void)ntb_msg_set_mask(perf->ntb, inbits | outbits); - if (use_dma && !pctx->dma_chan) { - dma_cap_mask_t dma_mask; + incmd_bit = BIT_ULL(__ffs64(inbits)); + ret = ntb_msg_clear_mask(perf->ntb, incmd_bit); - dma_cap_zero(dma_mask); - dma_cap_set(DMA_MEMCPY, dma_mask); - dma_chan = dma_request_channel(dma_mask, perf_dma_filter_fn, - (void *)(unsigned long)node); - if (!dma_chan) { - pr_warn("%s: cannot acquire DMA channel, quitting\n", - current->comm); - return -ENODEV; - } - pctx->dma_chan = dma_chan; + dev_dbg(&perf->ntb->dev, "MSG sts unmasked %#llx\n", incmd_bit); + } else { + scnt = ntb_spad_count(perf->ntb); + for (sidx = 0; sidx < scnt; sidx++) + ntb_spad_write(perf->ntb, sidx, PERF_CMD_INVAL); + incmd_bit = PERF_SPAD_NOTIFY(perf->gidx); + ret = ntb_db_clear_mask(perf->ntb, incmd_bit); + + dev_dbg(&perf->ntb->dev, "DB bits unmasked %#llx\n", incmd_bit); + } + if (ret) { + ntb_clear_ctx(perf->ntb); + return ret; } - for (i = 0; i < MAX_SRCS; i++) { - pctx->srcs[i] = kmalloc_node(MAX_TEST_SIZE, GFP_KERNEL, node); - if (!pctx->srcs[i]) { - rc = -ENOMEM; - goto err; - } + ntb_link_enable(perf->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); + /* Might be not necessary */ + ntb_link_event(perf->ntb); + + return 0; +} + +static void perf_disable_service(struct perf_ctx *perf) +{ + int pidx; + + ntb_link_disable(perf->ntb); + + if (perf->cmd_send == perf_msg_cmd_send) { + u64 inbits; + + inbits = ntb_msg_inbits(perf->ntb); + (void)ntb_msg_set_mask(perf->ntb, inbits); + } else { + (void)ntb_db_set_mask(perf->ntb, PERF_SPAD_NOTIFY(perf->gidx)); } - win_size = mw->phys_size; - buf_size = 1ULL << seg_order; - total = 1ULL << run_order; + ntb_clear_ctx(perf->ntb); - if (buf_size > MAX_TEST_SIZE) - buf_size = MAX_TEST_SIZE; + for (pidx = 0; pidx < perf->pcnt; pidx++) + perf_cmd_exec(&perf->peers[pidx], PERF_CMD_CLEAR); - dst = (char __iomem *)mw->vbase; + for (pidx = 0; pidx < perf->pcnt; pidx++) + flush_work(&perf->peers[pidx].service); +} - atomic_inc(&perf->tsync); - while (atomic_read(&perf->tsync) != perf->perf_threads) - schedule(); +/*============================================================================== + * Performance measuring work-thread + *============================================================================== + */ - src = pctx->srcs[pctx->src_idx]; - pctx->src_idx = (pctx->src_idx + 1) & (MAX_SRCS - 1); +static void perf_dma_copy_callback(void *data) +{ + struct perf_thread *pthr = data; - rc = perf_move_data(pctx, dst, src, buf_size, win_size, total); + atomic_dec(&pthr->dma_sync); + wake_up(&pthr->dma_wait); +} - atomic_dec(&perf->tsync); +static int perf_copy_chunk(struct perf_thread *pthr, + void __iomem *dst, void *src, size_t len) +{ + struct dma_async_tx_descriptor *tx; + struct dmaengine_unmap_data *unmap; + struct device *dma_dev; + int try = 0, ret = 0; - if (rc < 0) { - pr_err("%s: failed\n", current->comm); - rc = -ENXIO; - goto err; + if (!use_dma) { + memcpy_toio(dst, src, len); + goto ret_check_tsync; } - for (i = 0; i < MAX_SRCS; i++) { - kfree(pctx->srcs[i]); - pctx->srcs[i] = NULL; + dma_dev = pthr->dma_chan->device->dev; + + if (!is_dma_copy_aligned(pthr->dma_chan->device, offset_in_page(src), + offset_in_page(dst), len)) + return -EIO; + + unmap = dmaengine_get_unmap_data(dma_dev, 2, GFP_NOWAIT); + if (!unmap) + return -ENOMEM; + + unmap->len = len; + unmap->addr[0] = dma_map_page(dma_dev, virt_to_page(src), + offset_in_page(src), len, DMA_TO_DEVICE); + if (dma_mapping_error(dma_dev, unmap->addr[0])) { + ret = -EIO; + goto err_free_resource; } + unmap->to_cnt = 1; - atomic_inc(&perf->tdone); - wake_up(pctx->wq); - rc = 0; - goto done; + unmap->addr[1] = dma_map_page(dma_dev, virt_to_page(dst), + offset_in_page(dst), len, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_dev, unmap->addr[1])) { + ret = -EIO; + goto err_free_resource; + } + unmap->from_cnt = 1; -err: - for (i = 0; i < MAX_SRCS; i++) { - kfree(pctx->srcs[i]); - pctx->srcs[i] = NULL; + do { + tx = dmaengine_prep_dma_memcpy(pthr->dma_chan, unmap->addr[1], + unmap->addr[0], len, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx) + msleep(DMA_MDELAY); + } while (!tx && (try++ < DMA_TRIES)); + + if (!tx) { + ret = -EIO; + goto err_free_resource; } - if (dma_chan) { - dma_release_channel(dma_chan); - pctx->dma_chan = NULL; + tx->callback = perf_dma_copy_callback; + tx->callback_param = pthr; + dma_set_unmap(tx, unmap); + + if (dma_submit_error(dmaengine_submit(tx))) { + dmaengine_unmap_put(unmap); + goto err_free_resource; } -done: - /* Wait until we are told to stop */ - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) - break; - schedule(); + dmaengine_unmap_put(unmap); + + atomic_inc(&pthr->dma_sync); + dma_async_issue_pending(pthr->dma_chan); + +ret_check_tsync: + return likely(atomic_read(&pthr->perf->tsync) > 0) ? 0 : -EINTR; + +err_free_resource: + dmaengine_unmap_put(unmap); + + return ret; +} + +static bool perf_dma_filter(struct dma_chan *chan, void *data) +{ + struct perf_ctx *perf = data; + int node; + + node = dev_to_node(&perf->ntb->dev); + + return node == NUMA_NO_NODE || node == dev_to_node(chan->device->dev); +} + +static int perf_init_test(struct perf_thread *pthr) +{ + struct perf_ctx *perf = pthr->perf; + dma_cap_mask_t dma_mask; + + pthr->src = kmalloc_node(perf->test_peer->outbuf_size, GFP_KERNEL, + dev_to_node(&perf->ntb->dev)); + if (!pthr->src) + return -ENOMEM; + + get_random_bytes(pthr->src, perf->test_peer->outbuf_size); + + if (!use_dma) + return 0; + + dma_cap_zero(dma_mask); + dma_cap_set(DMA_MEMCPY, dma_mask); + pthr->dma_chan = dma_request_channel(dma_mask, perf_dma_filter, perf); + if (!pthr->dma_chan) { + dev_err(&perf->ntb->dev, "%d: Failed to get DMA channel\n", + pthr->tidx); + atomic_dec(&perf->tsync); + wake_up(&perf->twait); + kfree(pthr->src); + return -ENODEV; } - __set_current_state(TASK_RUNNING); - return rc; + atomic_set(&pthr->dma_sync, 0); + + return 0; } -static void perf_free_mw(struct perf_ctx *perf) +static int perf_run_test(struct perf_thread *pthr) { - struct perf_mw *mw = &perf->mw; - struct pci_dev *pdev = perf->ntb->pdev; + struct perf_peer *peer = pthr->perf->test_peer; + struct perf_ctx *perf = pthr->perf; + void __iomem *flt_dst, *bnd_dst; + u64 total_size, chunk_size; + void *flt_src; + int ret = 0; + + total_size = 1ULL << total_order; + chunk_size = 1ULL << chunk_order; + chunk_size = min_t(u64, peer->outbuf_size, chunk_size); + + flt_src = pthr->src; + bnd_dst = peer->outbuf + peer->outbuf_size; + flt_dst = peer->outbuf; + + pthr->duration = ktime_get(); + + /* Copied field is cleared on test launch stage */ + while (pthr->copied < total_size) { + ret = perf_copy_chunk(pthr, flt_dst, flt_src, chunk_size); + if (ret) { + dev_err(&perf->ntb->dev, "%d: Got error %d on test\n", + pthr->tidx, ret); + return ret; + } - if (!mw->virt_addr) - return; + pthr->copied += chunk_size; + + flt_dst += chunk_size; + flt_src += chunk_size; + if (flt_dst >= bnd_dst || flt_dst < peer->outbuf) { + flt_dst = peer->outbuf; + flt_src = pthr->src; + } - ntb_mw_clear_trans(perf->ntb, PIDX, 0); - dma_free_coherent(&pdev->dev, mw->buf_size, - mw->virt_addr, mw->dma_addr); - mw->xlat_size = 0; - mw->buf_size = 0; - mw->virt_addr = NULL; + /* Give up CPU to give a chance for other threads to use it */ + schedule(); + } + + return 0; } -static int perf_set_mw(struct perf_ctx *perf, resource_size_t size) +static int perf_sync_test(struct perf_thread *pthr) { - struct perf_mw *mw = &perf->mw; - size_t xlat_size, buf_size; - resource_size_t xlat_align; - resource_size_t xlat_align_size; - int rc; + struct perf_ctx *perf = pthr->perf; - if (!size) - return -EINVAL; + if (!use_dma) + goto no_dma_ret; - rc = ntb_mw_get_align(perf->ntb, PIDX, 0, &xlat_align, - &xlat_align_size, NULL); - if (rc) - return rc; + wait_event(pthr->dma_wait, + (atomic_read(&pthr->dma_sync) == 0 || + atomic_read(&perf->tsync) < 0)); - xlat_size = round_up(size, xlat_align_size); - buf_size = round_up(size, xlat_align); + if (atomic_read(&perf->tsync) < 0) + return -EINTR; - if (mw->xlat_size == xlat_size) - return 0; +no_dma_ret: + pthr->duration = ktime_sub(ktime_get(), pthr->duration); - if (mw->buf_size) - perf_free_mw(perf); + dev_dbg(&perf->ntb->dev, "%d: copied %llu bytes\n", + pthr->tidx, pthr->copied); - mw->xlat_size = xlat_size; - mw->buf_size = buf_size; + dev_dbg(&perf->ntb->dev, "%d: lasted %llu usecs\n", + pthr->tidx, ktime_to_us(pthr->duration)); + + dev_dbg(&perf->ntb->dev, "%d: %llu MBytes/s\n", pthr->tidx, + div64_u64(pthr->copied, ktime_to_us(pthr->duration))); + + return 0; +} + +static void perf_clear_test(struct perf_thread *pthr) +{ + struct perf_ctx *perf = pthr->perf; + + if (!use_dma) + goto no_dma_notify; + + /* + * If test finished without errors, termination isn't needed. + * We call it anyway just to be sure of the transfers completion. + */ + (void)dmaengine_terminate_sync(pthr->dma_chan); + + dma_release_channel(pthr->dma_chan); + +no_dma_notify: + atomic_dec(&perf->tsync); + wake_up(&perf->twait); + kfree(pthr->src); +} - mw->virt_addr = dma_alloc_coherent(&perf->ntb->pdev->dev, buf_size, - &mw->dma_addr, GFP_KERNEL); - if (!mw->virt_addr) { - mw->xlat_size = 0; - mw->buf_size = 0; +static void perf_thread_work(struct work_struct *work) +{ + struct perf_thread *pthr = to_thread_work(work); + int ret; + + /* + * Perform stages in compliance with use_dma flag value. + * Test status is changed only if error happened, otherwise + * status -ENODATA is kept while test is on-fly. Results + * synchronization is performed only if test fininshed + * without an error or interruption. + */ + ret = perf_init_test(pthr); + if (ret) { + pthr->status = ret; + return; } - rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size); - if (rc) { - dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n"); - perf_free_mw(perf); - return -EIO; + ret = perf_run_test(pthr); + if (ret) { + pthr->status = ret; + goto err_clear_test; } - return 0; + pthr->status = perf_sync_test(pthr); + +err_clear_test: + perf_clear_test(pthr); } -static void perf_link_work(struct work_struct *work) +static int perf_set_tcnt(struct perf_ctx *perf, u8 tcnt) { - struct perf_ctx *perf = - container_of(work, struct perf_ctx, link_work.work); - struct ntb_dev *ndev = perf->ntb; - struct pci_dev *pdev = ndev->pdev; - u32 val; - u64 size; - int rc; + if (tcnt == 0 || tcnt > MAX_THREADS_CNT) + return -EINVAL; - dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__); + if (test_and_set_bit_lock(0, &perf->busy_flag)) + return -EBUSY; + + perf->tcnt = tcnt; + + clear_bit_unlock(0, &perf->busy_flag); - size = perf->mw.phys_size; + return 0; +} - if (max_mw_size && size > max_mw_size) - size = max_mw_size; +static void perf_terminate_test(struct perf_ctx *perf) +{ + int tidx; - ntb_peer_spad_write(ndev, PIDX, MW_SZ_HIGH, upper_32_bits(size)); - ntb_peer_spad_write(ndev, PIDX, MW_SZ_LOW, lower_32_bits(size)); - ntb_peer_spad_write(ndev, PIDX, VERSION, PERF_VERSION); + atomic_set(&perf->tsync, -1); + wake_up(&perf->twait); - /* now read what peer wrote */ - val = ntb_spad_read(ndev, VERSION); - if (val != PERF_VERSION) { - dev_dbg(&pdev->dev, "Remote version = %#x\n", val); - goto out; + for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) { + wake_up(&perf->threads[tidx].dma_wait); + cancel_work_sync(&perf->threads[tidx].work); } +} + +static int perf_submit_test(struct perf_peer *peer) +{ + struct perf_ctx *perf = peer->perf; + struct perf_thread *pthr; + int tidx, ret; - val = ntb_spad_read(ndev, MW_SZ_HIGH); - size = (u64)val << 32; + if (!test_bit(PERF_STS_DONE, &peer->sts)) + return -ENOLINK; - val = ntb_spad_read(ndev, MW_SZ_LOW); - size |= val; + if (test_and_set_bit_lock(0, &perf->busy_flag)) + return -EBUSY; - dev_dbg(&pdev->dev, "Remote MW size = %#llx\n", size); + perf->test_peer = peer; + atomic_set(&perf->tsync, perf->tcnt); - rc = perf_set_mw(perf, size); - if (rc) - goto out1; + for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) { + pthr = &perf->threads[tidx]; - perf->link_is_up = true; - wake_up(&perf->link_wq); + pthr->status = -ENODATA; + pthr->copied = 0; + pthr->duration = ktime_set(0, 0); + if (tidx < perf->tcnt) + (void)queue_work(perf_wq, &pthr->work); + } - return; + ret = wait_event_interruptible(perf->twait, + atomic_read(&perf->tsync) <= 0); + if (ret == -ERESTARTSYS) { + perf_terminate_test(perf); + ret = -EINTR; + } -out1: - perf_free_mw(perf); + clear_bit_unlock(0, &perf->busy_flag); -out: - if (ntb_link_is_up(ndev, NULL, NULL) == 1) - schedule_delayed_work(&perf->link_work, - msecs_to_jiffies(PERF_LINK_DOWN_TIMEOUT)); + return ret; } -static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf) +static int perf_read_stats(struct perf_ctx *perf, char *buf, + size_t size, ssize_t *pos) { - struct perf_mw *mw; - int rc; + struct perf_thread *pthr; + int tidx; + + if (test_and_set_bit_lock(0, &perf->busy_flag)) + return -EBUSY; - mw = &perf->mw; + (*pos) += scnprintf(buf + *pos, size - *pos, + " Peer %d test statistics:\n", perf->test_peer->pidx); - rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size); - if (rc) - return rc; + for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) { + pthr = &perf->threads[tidx]; - perf->mw.vbase = ioremap_wc(mw->phys_addr, mw->phys_size); - if (!mw->vbase) - return -ENOMEM; + if (pthr->status == -ENODATA) + continue; + + if (pthr->status) { + (*pos) += scnprintf(buf + *pos, size - *pos, + "%d: error status %d\n", tidx, pthr->status); + continue; + } + + (*pos) += scnprintf(buf + *pos, size - *pos, + "%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n", + tidx, pthr->copied, ktime_to_us(pthr->duration), + div64_u64(pthr->copied, ktime_to_us(pthr->duration))); + } + + clear_bit_unlock(0, &perf->busy_flag); return 0; } -static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) +static void perf_init_threads(struct perf_ctx *perf) { - struct perf_ctx *perf = filp->private_data; + struct perf_thread *pthr; + int tidx; + + perf->tcnt = DEF_THREADS_CNT; + perf->test_peer = &perf->peers[0]; + init_waitqueue_head(&perf->twait); + + for (tidx = 0; tidx < MAX_THREADS_CNT; tidx++) { + pthr = &perf->threads[tidx]; + + pthr->perf = perf; + pthr->tidx = tidx; + pthr->status = -ENODATA; + init_waitqueue_head(&pthr->dma_wait); + INIT_WORK(&pthr->work, perf_thread_work); + } +} + +static void perf_clear_threads(struct perf_ctx *perf) +{ + perf_terminate_test(perf); +} + +/*============================================================================== + * DebugFS nodes + *============================================================================== + */ + +static ssize_t perf_dbgfs_read_info(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct perf_ctx *perf = filep->private_data; + struct perf_peer *peer; + size_t buf_size; + ssize_t pos = 0; + int ret, pidx; char *buf; - ssize_t ret, out_off = 0; - struct pthr_ctx *pctx; - int i; - u64 rate; - if (!perf) - return 0; + buf_size = min_t(size_t, size, 0x1000U); - buf = kmalloc(1024, GFP_KERNEL); + buf = kmalloc(buf_size, GFP_KERNEL); if (!buf) return -ENOMEM; - if (mutex_is_locked(&perf->run_mutex)) { - out_off = scnprintf(buf, 64, "running\n"); - goto read_from_buf; + pos += scnprintf(buf + pos, buf_size - pos, + " Performance measuring tool info:\n\n"); + + pos += scnprintf(buf + pos, buf_size - pos, + "Local port %d, Global index %d\n", ntb_port_number(perf->ntb), + perf->gidx); + pos += scnprintf(buf + pos, buf_size - pos, "Test status: "); + if (test_bit(0, &perf->busy_flag)) { + pos += scnprintf(buf + pos, buf_size - pos, + "on-fly with port %d (%d)\n", + ntb_peer_port_number(perf->ntb, perf->test_peer->pidx), + perf->test_peer->pidx); + } else { + pos += scnprintf(buf + pos, buf_size - pos, "idle\n"); } - for (i = 0; i < MAX_THREADS; i++) { - pctx = &perf->pthr_ctx[i]; + for (pidx = 0; pidx < perf->pcnt; pidx++) { + peer = &perf->peers[pidx]; + + pos += scnprintf(buf + pos, buf_size - pos, + "Port %d (%d), Global index %d:\n", + ntb_peer_port_number(perf->ntb, peer->pidx), peer->pidx, + peer->gidx); + + pos += scnprintf(buf + pos, buf_size - pos, + "\tLink status: %s\n", + test_bit(PERF_STS_LNKUP, &peer->sts) ? "up" : "down"); + + pos += scnprintf(buf + pos, buf_size - pos, + "\tOut buffer addr 0x%pK\n", peer->outbuf); - if (pctx->status == -ENODATA) - break; + pos += scnprintf(buf + pos, buf_size - pos, + "\tOut buffer size %pa\n", &peer->outbuf_size); - if (pctx->status) { - out_off += scnprintf(buf + out_off, 1024 - out_off, - "%d: error %d\n", i, - pctx->status); + pos += scnprintf(buf + pos, buf_size - pos, + "\tOut buffer xlat 0x%016llx[p]\n", peer->outbuf_xlat); + + if (!peer->inbuf) { + pos += scnprintf(buf + pos, buf_size - pos, + "\tIn buffer addr: unallocated\n"); continue; } - rate = div64_u64(pctx->copied, pctx->diff_us); - out_off += scnprintf(buf + out_off, 1024 - out_off, - "%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n", - i, pctx->copied, pctx->diff_us, rate); + pos += scnprintf(buf + pos, buf_size - pos, + "\tIn buffer addr 0x%pK\n", peer->inbuf); + + pos += scnprintf(buf + pos, buf_size - pos, + "\tIn buffer size %pa\n", &peer->inbuf_size); + + pos += scnprintf(buf + pos, buf_size - pos, + "\tIn buffer xlat %pad[p]\n", &peer->inbuf_xlat); } -read_from_buf: - ret = simple_read_from_buffer(ubuf, count, offp, buf, out_off); + ret = simple_read_from_buffer(ubuf, size, offp, buf, pos); kfree(buf); return ret; } -static void threads_cleanup(struct perf_ctx *perf) +static const struct file_operations perf_dbgfs_info = { + .open = simple_open, + .read = perf_dbgfs_read_info +}; + +static ssize_t perf_dbgfs_read_run(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) { - struct pthr_ctx *pctx; - int i; + struct perf_ctx *perf = filep->private_data; + ssize_t ret, pos = 0; + char *buf; - for (i = 0; i < MAX_THREADS; i++) { - pctx = &perf->pthr_ctx[i]; - if (pctx->thread) { - pctx->status = kthread_stop(pctx->thread); - pctx->thread = NULL; - } - } -} + buf = kmalloc(PERF_BUF_LEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; -static void perf_clear_thread_status(struct perf_ctx *perf) -{ - int i; + ret = perf_read_stats(perf, buf, PERF_BUF_LEN, &pos); + if (ret) + goto err_free; + + ret = simple_read_from_buffer(ubuf, size, offp, buf, pos); +err_free: + kfree(buf); - for (i = 0; i < MAX_THREADS; i++) - perf->pthr_ctx[i].status = -ENODATA; + return ret; } -static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf, - size_t count, loff_t *offp) +static ssize_t perf_dbgfs_write_run(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) { - struct perf_ctx *perf = filp->private_data; - int node, i; - DECLARE_WAIT_QUEUE_HEAD(wq); + struct perf_ctx *perf = filep->private_data; + struct perf_peer *peer; + int pidx, ret; - if (wait_event_interruptible(perf->link_wq, perf->link_is_up)) - return -ENOLINK; + ret = kstrtoint_from_user(ubuf, size, 0, &pidx); + if (ret) + return ret; - if (perf->perf_threads == 0) + if (pidx < 0 || pidx >= perf->pcnt) return -EINVAL; - if (!mutex_trylock(&perf->run_mutex)) - return -EBUSY; + peer = &perf->peers[pidx]; - perf_clear_thread_status(perf); + ret = perf_submit_test(peer); + if (ret) + return ret; - if (perf->perf_threads > MAX_THREADS) { - perf->perf_threads = MAX_THREADS; - pr_info("Reset total threads to: %u\n", MAX_THREADS); - } + return size; +} - /* no greater than 1M */ - if (seg_order > MAX_SEG_ORDER) { - seg_order = MAX_SEG_ORDER; - pr_info("Fix seg_order to %u\n", seg_order); - } +static const struct file_operations perf_dbgfs_run = { + .open = simple_open, + .read = perf_dbgfs_read_run, + .write = perf_dbgfs_write_run +}; - if (run_order < seg_order) { - run_order = seg_order; - pr_info("Fix run_order to %u\n", run_order); - } +static ssize_t perf_dbgfs_read_tcnt(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct perf_ctx *perf = filep->private_data; + char buf[8]; + ssize_t pos; - node = on_node ? dev_to_node(&perf->ntb->pdev->dev) - : NUMA_NO_NODE; - atomic_set(&perf->tdone, 0); + pos = scnprintf(buf, sizeof(buf), "%hhu\n", perf->tcnt); - /* launch kernel thread */ - for (i = 0; i < perf->perf_threads; i++) { - struct pthr_ctx *pctx; + return simple_read_from_buffer(ubuf, size, offp, buf, pos); +} - pctx = &perf->pthr_ctx[i]; - atomic_set(&pctx->dma_sync, 0); - pctx->perf = perf; - pctx->wq = &wq; - pctx->thread = - kthread_create_on_node(ntb_perf_thread, - (void *)pctx, - node, "ntb_perf %d", i); - if (IS_ERR(pctx->thread)) { - pctx->thread = NULL; - goto err; - } else { - wake_up_process(pctx->thread); - } - } +static ssize_t perf_dbgfs_write_tcnt(struct file *filep, + const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct perf_ctx *perf = filep->private_data; + int ret; + u8 val; - wait_event_interruptible(wq, - atomic_read(&perf->tdone) == perf->perf_threads); + ret = kstrtou8_from_user(ubuf, size, 0, &val); + if (ret) + return ret; - threads_cleanup(perf); - mutex_unlock(&perf->run_mutex); - return count; + ret = perf_set_tcnt(perf, val); + if (ret) + return ret; -err: - threads_cleanup(perf); - mutex_unlock(&perf->run_mutex); - return -ENXIO; + return size; } -static const struct file_operations ntb_perf_debugfs_run = { - .owner = THIS_MODULE, +static const struct file_operations perf_dbgfs_tcnt = { .open = simple_open, - .read = debugfs_run_read, - .write = debugfs_run_write, + .read = perf_dbgfs_read_tcnt, + .write = perf_dbgfs_write_tcnt }; -static int perf_debugfs_setup(struct perf_ctx *perf) +static void perf_setup_dbgfs(struct perf_ctx *perf) { struct pci_dev *pdev = perf->ntb->pdev; - struct dentry *debugfs_node_dir; - struct dentry *debugfs_run; - struct dentry *debugfs_threads; - struct dentry *debugfs_seg_order; - struct dentry *debugfs_run_order; - struct dentry *debugfs_use_dma; - struct dentry *debugfs_on_node; - - if (!debugfs_initialized()) - return -ENODEV; - /* Assumpion: only one NTB device in the system */ - if (!perf_debugfs_dir) { - perf_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!perf_debugfs_dir) - return -ENODEV; - } - - debugfs_node_dir = debugfs_create_dir(pci_name(pdev), - perf_debugfs_dir); - if (!debugfs_node_dir) - goto err; - - debugfs_run = debugfs_create_file("run", S_IRUSR | S_IWUSR, - debugfs_node_dir, perf, - &ntb_perf_debugfs_run); - if (!debugfs_run) - goto err; - - debugfs_threads = debugfs_create_u8("threads", S_IRUSR | S_IWUSR, - debugfs_node_dir, - &perf->perf_threads); - if (!debugfs_threads) - goto err; - - debugfs_seg_order = debugfs_create_u32("seg_order", 0600, - debugfs_node_dir, - &seg_order); - if (!debugfs_seg_order) - goto err; - - debugfs_run_order = debugfs_create_u32("run_order", 0600, - debugfs_node_dir, - &run_order); - if (!debugfs_run_order) - goto err; - - debugfs_use_dma = debugfs_create_bool("use_dma", 0600, - debugfs_node_dir, - &use_dma); - if (!debugfs_use_dma) - goto err; - - debugfs_on_node = debugfs_create_bool("on_node", 0600, - debugfs_node_dir, - &on_node); - if (!debugfs_on_node) - goto err; + perf->dbgfs_dir = debugfs_create_dir(pci_name(pdev), perf_dbgfs_topdir); + if (!perf->dbgfs_dir) { + dev_warn(&perf->ntb->dev, "DebugFS unsupported\n"); + return; + } + + debugfs_create_file("info", 0600, perf->dbgfs_dir, perf, + &perf_dbgfs_info); - return 0; + debugfs_create_file("run", 0600, perf->dbgfs_dir, perf, + &perf_dbgfs_run); -err: - debugfs_remove_recursive(perf_debugfs_dir); - perf_debugfs_dir = NULL; - return -ENODEV; + debugfs_create_file("threads_count", 0600, perf->dbgfs_dir, perf, + &perf_dbgfs_tcnt); + + /* They are made read-only for test exec safety and integrity */ + debugfs_create_u8("chunk_order", 0500, perf->dbgfs_dir, &chunk_order); + + debugfs_create_u8("total_order", 0500, perf->dbgfs_dir, &total_order); + + debugfs_create_bool("use_dma", 0500, perf->dbgfs_dir, &use_dma); } -static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb) +static void perf_clear_dbgfs(struct perf_ctx *perf) +{ + debugfs_remove_recursive(perf->dbgfs_dir); +} + +/*============================================================================== + * Basic driver initialization + *============================================================================== + */ + +static struct perf_ctx *perf_create_data(struct ntb_dev *ntb) { - struct pci_dev *pdev = ntb->pdev; struct perf_ctx *perf; - int node; - int rc = 0; - if (ntb_spad_count(ntb) < MAX_SPAD) { - dev_err(&ntb->dev, "Not enough scratch pad registers for %s", - DRIVER_NAME); - return -EIO; - } + perf = devm_kzalloc(&ntb->dev, sizeof(*perf), GFP_KERNEL); + if (!perf) + return ERR_PTR(-ENOMEM); - if (!ntb->ops->mw_set_trans) { - dev_err(&ntb->dev, "Need inbound MW based NTB API\n"); - return -EINVAL; + perf->pcnt = ntb_peer_port_count(ntb); + perf->peers = devm_kcalloc(&ntb->dev, perf->pcnt, sizeof(*perf->peers), + GFP_KERNEL); + if (!perf->peers) + return ERR_PTR(-ENOMEM); + + perf->ntb = ntb; + + return perf; +} + +static int perf_setup_peer_mw(struct perf_peer *peer) +{ + struct perf_ctx *perf = peer->perf; + phys_addr_t phys_addr; + int ret; + + /* Get outbound MW parameters and map it */ + ret = ntb_peer_mw_get_addr(perf->ntb, peer->gidx, &phys_addr, + &peer->outbuf_size); + if (ret) + return ret; + + peer->outbuf = devm_ioremap_wc(&perf->ntb->dev, phys_addr, + peer->outbuf_size); + if (!peer->outbuf) + return -ENOMEM; + + if (max_mw_size && peer->outbuf_size > max_mw_size) { + peer->outbuf_size = max_mw_size; + dev_warn(&peer->perf->ntb->dev, + "Peer %d outbuf reduced to %#llx\n", peer->pidx, + peer->outbuf_size); } - if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) - dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n"); + return 0; +} - node = on_node ? dev_to_node(&pdev->dev) : NUMA_NO_NODE; - perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node); - if (!perf) { - rc = -ENOMEM; - goto err_perf; +static int perf_init_peers(struct perf_ctx *perf) +{ + struct perf_peer *peer; + int pidx, lport, ret; + + lport = ntb_port_number(perf->ntb); + perf->gidx = -1; + for (pidx = 0; pidx < perf->pcnt; pidx++) { + peer = &perf->peers[pidx]; + + peer->perf = perf; + peer->pidx = pidx; + if (lport < ntb_peer_port_number(perf->ntb, pidx)) { + if (perf->gidx == -1) + perf->gidx = pidx; + peer->gidx = pidx + 1; + } else { + peer->gidx = pidx; + } + INIT_WORK(&peer->service, perf_service_work); } + if (perf->gidx == -1) + perf->gidx = pidx; - perf->ntb = ntb; - perf->perf_threads = 1; - atomic_set(&perf->tsync, 0); - mutex_init(&perf->run_mutex); - spin_lock_init(&perf->db_lock); - perf_setup_mw(ntb, perf); - init_waitqueue_head(&perf->link_wq); - INIT_DELAYED_WORK(&perf->link_work, perf_link_work); + for (pidx = 0; pidx < perf->pcnt; pidx++) { + ret = perf_setup_peer_mw(&perf->peers[pidx]); + if (ret) + return ret; + } + + dev_dbg(&perf->ntb->dev, "Global port index %d\n", perf->gidx); + + return 0; +} - rc = ntb_set_ctx(ntb, perf, &perf_ops); - if (rc) - goto err_ctx; +static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb) +{ + struct perf_ctx *perf; + int ret; - perf->link_is_up = false; - ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); - ntb_link_event(ntb); + perf = perf_create_data(ntb); + if (IS_ERR(perf)) + return PTR_ERR(perf); - rc = perf_debugfs_setup(perf); - if (rc) - goto err_ctx; + ret = perf_init_peers(perf); + if (ret) + return ret; - perf_clear_thread_status(perf); + perf_init_threads(perf); - return 0; + ret = perf_init_service(perf); + if (ret) + return ret; -err_ctx: - cancel_delayed_work_sync(&perf->link_work); - kfree(perf); -err_perf: - return rc; + ret = perf_enable_service(perf); + if (ret) + return ret; + + perf_setup_dbgfs(perf); + + return 0; } static void perf_remove(struct ntb_client *client, struct ntb_dev *ntb) { struct perf_ctx *perf = ntb->ctx; - int i; - dev_dbg(&perf->ntb->dev, "%s called\n", __func__); + perf_clear_dbgfs(perf); - mutex_lock(&perf->run_mutex); + perf_disable_service(perf); - cancel_delayed_work_sync(&perf->link_work); + perf_clear_threads(perf); +} - ntb_clear_ctx(ntb); - ntb_link_disable(ntb); +static struct ntb_client perf_client = { + .ops = { + .probe = perf_probe, + .remove = perf_remove + } +}; - debugfs_remove_recursive(perf_debugfs_dir); - perf_debugfs_dir = NULL; +static int __init perf_init(void) +{ + int ret; - if (use_dma) { - for (i = 0; i < MAX_THREADS; i++) { - struct pthr_ctx *pctx = &perf->pthr_ctx[i]; + if (chunk_order > MAX_CHUNK_ORDER) { + chunk_order = MAX_CHUNK_ORDER; + pr_info("Chunk order reduced to %hhu\n", chunk_order); + } - if (pctx->dma_chan) - dma_release_channel(pctx->dma_chan); - } + if (total_order < chunk_order) { + total_order = chunk_order; + pr_info("Total data order reduced to %hhu\n", total_order); } - kfree(perf); + perf_wq = alloc_workqueue("perf_wq", WQ_UNBOUND | WQ_SYSFS, 0); + if (!perf_wq) + return -ENOMEM; + + if (debugfs_initialized()) + perf_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + ret = ntb_register_client(&perf_client); + if (ret) { + debugfs_remove_recursive(perf_dbgfs_topdir); + destroy_workqueue(perf_wq); + } + + return ret; } +module_init(perf_init); + +static void __exit perf_exit(void) +{ + ntb_unregister_client(&perf_client); + debugfs_remove_recursive(perf_dbgfs_topdir); + destroy_workqueue(perf_wq); +} +module_exit(perf_exit); -static struct ntb_client perf_client = { - .ops = { - .probe = perf_probe, - .remove = perf_remove, - }, -}; -module_ntb_client(perf_client); -- cgit From 6952c6de8a350ef6052f3ae33499b947819df913 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 6 Dec 2017 17:32:06 +0300 Subject: NTB: ntb_hw_idt: Set NTB_TOPO_SWITCH topology Since Switchtec patch there has been a new topology added to the NTB API. It's called NTB_TOPO_SWITCH and dedicated for PCIe switch chips. Even though topo field isn't used within the IDT driver much, lets set it for the sake of unification. Signed-off-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/hw/idt/ntb_hw_idt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index 93d4c9d2a9ad..8d98872d0983 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -2070,7 +2070,7 @@ static int idt_register_device(struct idt_ntb_dev *ndev) /* Initialize the rest of NTB device structure and register it */ ndev->ntb.ops = &idt_ntb_ops; - ndev->ntb.topo = NTB_TOPO_PRI; + ndev->ntb.topo = NTB_TOPO_SWITCH; ret = ntb_register_device(&ndev->ntb); if (ret != 0) { -- cgit From 1536dc063e82090c5da65ddd94b1da1b38bfab43 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 19 Jan 2018 15:55:28 +0100 Subject: NTB: ntb_perf: fix printing of resource_size_t On 32-bit architectures, resource_size_t is usually 'unsigned int' or 'unsigned long' but not 'unsigned long long', so we get a warning about printing the wrong data: drivers/ntb/test/ntb_perf.c: In function 'perf_setup_peer_mw': drivers/ntb/test/ntb_perf.c:1390:35: error: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'resource_size_t {aka unsigned int}' [-Werror=format=] This changes the format string to the special %pa that is already used elsewhere in the same file. Fixes: b83003b3fdc1 ("NTB: ntb_perf: Add full multi-port NTB API support") Signed-off-by: Arnd Bergmann Signed-off-by: Jon Mason --- drivers/ntb/test/ntb_perf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c index 8de72f3fba4d..1829a17dd461 100644 --- a/drivers/ntb/test/ntb_perf.c +++ b/drivers/ntb/test/ntb_perf.c @@ -1387,8 +1387,8 @@ static int perf_setup_peer_mw(struct perf_peer *peer) if (max_mw_size && peer->outbuf_size > max_mw_size) { peer->outbuf_size = max_mw_size; dev_warn(&peer->perf->ntb->dev, - "Peer %d outbuf reduced to %#llx\n", peer->pidx, - peer->outbuf_size); + "Peer %d outbuf reduced to %pa\n", peer->pidx, + &peer->outbuf_size); } return 0; -- cgit From 2e2bc5a9a300261853303c006b7c29faafc64221 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 22 Jan 2018 09:38:57 +0000 Subject: NTB: ntb_tool: fix memory leak on 'buf' on error exit path Currently there is a memory leak on buf when the call to ntb_mw_get_align fails. Add an exit err label and jump to this so that kfree on buf frees the memory. Detected by CoverityScan, CID#1464286 ("Resource leak") Fixes: d637628ce00c ("NTB: ntb_tool: Add full multi-port NTB API support") Signed-off-by: Colin Ian King Acked-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/test/ntb_tool.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c index 920fc9b161b0..d592c0ffbd19 100644 --- a/drivers/ntb/test/ntb_tool.c +++ b/drivers/ntb/test/ntb_tool.c @@ -659,7 +659,7 @@ static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf, ret = ntb_mw_get_align(inmw->tc->ntb, inmw->pidx, inmw->widx, &addr_align, &size_align, &size_max); if (ret) - return ret; + goto err; off += scnprintf(buf + off, buf_size - off, "Inbound MW \t%d\n", @@ -694,6 +694,8 @@ static ssize_t tool_mw_trans_read(struct file *filep, char __user *ubuf, &size_max); ret = simple_read_from_buffer(ubuf, size, offp, buf, off); + +err: kfree(buf); return ret; -- cgit From ae07abdb84b267627f6e10fb813e62de5c3c8117 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 23 Jan 2018 02:09:21 +0000 Subject: ntb_hw_switchtec: Make function switchtec_ntb_remove() static Fixes the following sparse warnings: drivers/ntb/hw/mscc/ntb_hw_switchtec.c:1552:6: warning: symbol 'switchtec_ntb_remove' was not declared. Should it be static? Signed-off-by: Wei Yongjun Reviewed-by: Logan Gunthorpe Signed-off-by: Jon Mason --- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index a1d547b6aa12..f624ae27eabe 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1549,8 +1549,8 @@ free_and_exit: return rc; } -void switchtec_ntb_remove(struct device *dev, - struct class_interface *class_intf) +static void switchtec_ntb_remove(struct device *dev, + struct class_interface *class_intf) { struct switchtec_dev *stdev = to_stdev(dev); struct switchtec_ntb *sndev = stdev->sndev; -- cgit From cd20dc3ca75f17fd391e825b1606050bd62703fc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 23 Jan 2018 11:33:56 +0300 Subject: ntb_perf: Fix an error code in perf_copy_chunk() We accidentally return success if dmaengine_submit() fails. The fix is to preserve the error code from dma_submit_error(). Signed-off-by: Dan Carpenter Acked-by: Serge Semin Signed-off-by: Jon Mason --- drivers/ntb/test/ntb_perf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c index 1829a17dd461..b376609ffadb 100644 --- a/drivers/ntb/test/ntb_perf.c +++ b/drivers/ntb/test/ntb_perf.c @@ -828,7 +828,8 @@ static int perf_copy_chunk(struct perf_thread *pthr, tx->callback_param = pthr; dma_set_unmap(tx, unmap); - if (dma_submit_error(dmaengine_submit(tx))) { + ret = dma_submit_error(dmaengine_submit(tx)); + if (ret) { dmaengine_unmap_put(unmap); goto err_free_resource; } -- cgit From 3b28c987fb9547ca9aac73241d0e281cf646387c Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Jan 2018 10:48:45 +0300 Subject: NTB: ntb_perf: fix cast to restricted __le32 Sparse is whining about the u32 and __le32 mixed usage in the driver drivers/ntb/test/ntb_perf.c:288:21: warning: cast to restricted __le32 drivers/ntb/test/ntb_perf.c:295:37: warning: incorrect type in argument 4 (different base types) drivers/ntb/test/ntb_perf.c:295:37: expected unsigned int [unsigned] [usertype] val drivers/ntb/test/ntb_perf.c:295:37: got restricted __le32 [usertype] ... NTB hardware drivers shall accept CPU-endian data and translate it to the portable formate by internal means, so the explicit conversions are not necessary before Scratchpad/Messages API usage anymore. Fixes: b83003b3fdc1 ("NTB: ntb_perf: Add full multi-port NTB API support") Signed-off-by: Serge Semin Acked-by: Arnd Bergmann Signed-off-by: Jon Mason --- drivers/ntb/test/ntb_perf.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c index b376609ffadb..2a9d6b0d1f19 100644 --- a/drivers/ntb/test/ntb_perf.c +++ b/drivers/ntb/test/ntb_perf.c @@ -273,21 +273,21 @@ static int perf_spad_cmd_send(struct perf_peer *peer, enum perf_cmd cmd, sts = ntb_peer_spad_read(perf->ntb, peer->pidx, PERF_SPAD_CMD(perf->gidx)); - if (le32_to_cpu(sts) != PERF_CMD_INVAL) { + if (sts != PERF_CMD_INVAL) { usleep_range(MSG_UDELAY_LOW, MSG_UDELAY_HIGH); continue; } ntb_peer_spad_write(perf->ntb, peer->pidx, PERF_SPAD_LDATA(perf->gidx), - cpu_to_le32(lower_32_bits(data))); + lower_32_bits(data)); ntb_peer_spad_write(perf->ntb, peer->pidx, PERF_SPAD_HDATA(perf->gidx), - cpu_to_le32(upper_32_bits(data))); + upper_32_bits(data)); mmiowb(); ntb_peer_spad_write(perf->ntb, peer->pidx, PERF_SPAD_CMD(perf->gidx), - cpu_to_le32(cmd)); + cmd); mmiowb(); ntb_peer_db_set(perf->ntb, PERF_SPAD_NOTIFY(peer->gidx)); @@ -321,21 +321,20 @@ static int perf_spad_cmd_recv(struct perf_ctx *perf, int *pidx, continue; val = ntb_spad_read(perf->ntb, PERF_SPAD_CMD(peer->gidx)); - val = le32_to_cpu(val); if (val == PERF_CMD_INVAL) continue; *cmd = val; val = ntb_spad_read(perf->ntb, PERF_SPAD_LDATA(peer->gidx)); - *data = le32_to_cpu(val); + *data = val; val = ntb_spad_read(perf->ntb, PERF_SPAD_HDATA(peer->gidx)); - *data |= (u64)le32_to_cpu(val) << 32; + *data |= (u64)val << 32; /* Next command can be retrieved from now */ ntb_spad_write(perf->ntb, PERF_SPAD_CMD(peer->gidx), - cpu_to_le32(PERF_CMD_INVAL)); + PERF_CMD_INVAL); dev_dbg(&perf->ntb->dev, "CMD recv: %d 0x%llx\n", *cmd, *data); @@ -371,7 +370,7 @@ static int perf_msg_cmd_send(struct perf_peer *peer, enum perf_cmd cmd, return ret; ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_LDATA, - cpu_to_le32(lower_32_bits(data))); + lower_32_bits(data)); if (ntb_msg_read_sts(perf->ntb) & outbits) { usleep_range(MSG_UDELAY_LOW, MSG_UDELAY_HIGH); @@ -379,12 +378,11 @@ static int perf_msg_cmd_send(struct perf_peer *peer, enum perf_cmd cmd, } ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_HDATA, - cpu_to_le32(upper_32_bits(data))); + upper_32_bits(data)); mmiowb(); /* This call shall trigger peer message event */ - ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_CMD, - cpu_to_le32(cmd)); + ntb_peer_msg_write(perf->ntb, peer->pidx, PERF_MSG_CMD, cmd); break; } @@ -404,13 +402,13 @@ static int perf_msg_cmd_recv(struct perf_ctx *perf, int *pidx, return -ENODATA; val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_CMD); - *cmd = le32_to_cpu(val); + *cmd = val; val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_LDATA); - *data = le32_to_cpu(val); + *data = val; val = ntb_msg_read(perf->ntb, pidx, PERF_MSG_HDATA); - *data |= (u64)le32_to_cpu(val) << 32; + *data |= (u64)val << 32; /* Next command can be retrieved from now */ ntb_msg_clear_sts(perf->ntb, inbits); -- cgit From 8de50dc26278a05363781514beb092a366c84654 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 30 Nov 2017 09:45:00 +0100 Subject: irqchip/stm32: Fix copyright Uniformize STMicroelectronics copyrights header and add SPDX identifier CC: Maxime Coquelin Signed-off-by: Benjamin Gaignard Signed-off-by: Thomas Gleixner Acked-by: Alexandre TORGUE Acked-by: Maxime Coquelin Cc: jason@lakedaemon.net Cc: marc.zyngier@arm.com Cc: linux-arm-kernel@lists.infradead.org Link: https://lkml.kernel.org/r/20171130084500.23439-1-benjamin.gaignard@st.com --- drivers/irqchip/irq-stm32-exti.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 31ab0dee2ce7..36f0fbe36c35 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -1,7 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics 2017 * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 */ #include -- cgit From 02e389e63e3523828fc3832f27e0341885f60f6f Mon Sep 17 00:00:00 2001 From: Dmitry Mastykin Date: Thu, 28 Dec 2017 18:19:24 +0300 Subject: pinctrl: mcp23s08: fix irq setup order When using mcp23s08 module with gpio-keys, often (50% of boots) it fails to get irq numbers with message: "gpio-keys keys: Unable to get irq number for GPIO 0, error -6". Seems that irqs must be setup before devm_gpiochip_add_data(). Cc: stable@vger.kernel.org Signed-off-by: Dmitry Mastykin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-mcp23s08.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 95d548f3ba53..644c5beb05cb 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -890,16 +890,16 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, goto fail; } - ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp); - if (ret < 0) - goto fail; - if (mcp->irq && mcp->irq_controller) { ret = mcp23s08_irq_setup(mcp); if (ret) goto fail; } + ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp); + if (ret < 0) + goto fail; + mcp->pinctrl_desc.name = "mcp23xxx-pinctrl"; mcp->pinctrl_desc.pctlops = &mcp_pinctrl_ops; mcp->pinctrl_desc.confops = &mcp_pinconf_ops; -- cgit From 8914a595110a6eca69a5e275b323f5d09e18f4f9 Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Wed, 31 Jan 2018 14:15:34 +1100 Subject: bnx2x: disable GSO where gso_size is too big for hardware If a bnx2x card is passed a GSO packet with a gso_size larger than ~9700 bytes, it will cause a firmware error that will bring the card down: bnx2x: [bnx2x_attn_int_deasserted3:4323(enP24p1s0f0)]MC assert! bnx2x: [bnx2x_mc_assert:720(enP24p1s0f0)]XSTORM_ASSERT_LIST_INDEX 0x2 bnx2x: [bnx2x_mc_assert:736(enP24p1s0f0)]XSTORM_ASSERT_INDEX 0x0 = 0x00000000 0x25e43e47 0x00463e01 0x00010052 bnx2x: [bnx2x_mc_assert:750(enP24p1s0f0)]Chip Revision: everest3, FW Version: 7_13_1 ... (dump of values continues) ... Detect when the mac length of a GSO packet is greater than the maximum packet size (9700 bytes) and disable GSO. Signed-off-by: Daniel Axtens Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 7b08323e3f3d..74fc9af4aadb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12934,6 +12934,24 @@ static netdev_features_t bnx2x_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { + /* + * A skb with gso_size + header length > 9700 will cause a + * firmware panic. Drop GSO support. + * + * Eventually the upper layer should not pass these packets down. + * + * For speed, if the gso_size is <= 9000, assume there will + * not be 700 bytes of headers and pass it through. Only do a + * full (slow) validation if the gso_size is > 9000. + * + * (Due to the way SKB_BY_FRAGS works this will also do a full + * validation in that case.) + */ + if (unlikely(skb_is_gso(skb) && + (skb_shinfo(skb)->gso_size > 9000) && + !skb_gso_validate_mac_len(skb, 9700))) + features &= ~NETIF_F_GSO_MASK; + features = vlan_features_check(skb, features); return vxlan_features_check(skb, features); } -- cgit From 2e85283dabc22f4715b136e8a7426bd9bef4ce69 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 31 Jan 2018 16:14:25 +0000 Subject: be2net: remove redundant initialization of 'head' and pointer txq Variable head is initialized to a value that is never read and is being updated to a new value a few lines later, hence this initialization is redundant and can be safely removed as well as the now unused pointer txq. Cleans up clang warning: drivers/net/ethernet/emulex/benet/be_main.c:996:6: warning: Value stored to 'head' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index c36c81959198..d81e2d37bc3d 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -991,9 +991,8 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, { u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb); struct device *dev = &adapter->pdev->dev; - struct be_queue_info *txq = &txo->q; bool map_single = false; - u32 head = txq->head; + u32 head; dma_addr_t busaddr; int len; -- cgit From a83165f00f16c0e0ef5b7cec3cbd0d4788699265 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Feb 2018 12:21:15 +0100 Subject: rocker: fix possible null pointer dereference in rocker_router_fib_event_work Currently, rocker user may experience following null pointer derefence bug: [ 3.062141] BUG: unable to handle kernel NULL pointer dereference at 00000000000000d0 [ 3.065163] IP: rocker_router_fib_event_work+0x36/0x110 [rocker] The problem is uninitialized rocker->wops pointer that is initialized only with the first initialized port. So move the port initialization before registering the fib events. Fixes: 936bd486564a ("rocker: use FIB notifications instead of switchdev calls") Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker_main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index fc8f8bdf6579..056cb6093630 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2902,6 +2902,12 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_alloc_ordered_workqueue; } + err = rocker_probe_ports(rocker); + if (err) { + dev_err(&pdev->dev, "failed to probe ports\n"); + goto err_probe_ports; + } + /* Only FIBs pointing to our own netdevs are programmed into * the device, so no need to pass a callback. */ @@ -2918,22 +2924,16 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) rocker->hw.id = rocker_read64(rocker, SWITCH_ID); - err = rocker_probe_ports(rocker); - if (err) { - dev_err(&pdev->dev, "failed to probe ports\n"); - goto err_probe_ports; - } - dev_info(&pdev->dev, "Rocker switch with id %*phN\n", (int)sizeof(rocker->hw.id), &rocker->hw.id); return 0; -err_probe_ports: - unregister_switchdev_notifier(&rocker_switchdev_notifier); err_register_switchdev_notifier: unregister_fib_notifier(&rocker->fib_nb); err_register_fib_notifier: + rocker_remove_ports(rocker); +err_probe_ports: destroy_workqueue(rocker->rocker_owq); err_alloc_ordered_workqueue: free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker); @@ -2961,9 +2961,9 @@ static void rocker_remove(struct pci_dev *pdev) { struct rocker *rocker = pci_get_drvdata(pdev); - rocker_remove_ports(rocker); unregister_switchdev_notifier(&rocker_switchdev_notifier); unregister_fib_notifier(&rocker->fib_nb); + rocker_remove_ports(rocker); rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); destroy_workqueue(rocker->rocker_owq); free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker); -- cgit From f14d244f6147066c65dd98caa08aab0135ab1cc4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 1 Feb 2018 16:58:42 +0000 Subject: net: jme: remove unused initialization of 'rxdesc' Pointer rxdesc is assigned a value that is never read, it is overwritten by a new assignment inside a while loop hence the initial assignment is redundant and can be removed. Cleans up clang warning: drivers/net/ethernet/jme.c:1074:17: warning: Value stored to 'rxdesc' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/jme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 62d848df26ef..8a165842fa85 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -1071,7 +1071,7 @@ static int jme_process_receive(struct jme_adapter *jme, int limit) { struct jme_ring *rxring = &(jme->rxring[0]); - struct rxdesc *rxdesc = rxring->desc; + struct rxdesc *rxdesc; int i, j, ccnt, desccnt, mask = jme->rx_ring_mask; if (unlikely(!atomic_dec_and_test(&jme->rx_cleaning))) -- cgit From 3b51cc75eba28a7b2ca013f8255a4fd425b12b26 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 1 Feb 2018 17:10:18 +0000 Subject: lan78xx: remove redundant initialization of pointer 'phydev' Pointer phydev is initialized and this value is never read, phydev is immediately updated to a new value, hence this initialization is redundant and can be removed Cleans up clang warning: drivers/net/usb/lan78xx.c:2009:21: warning: Value stored to 'phydev' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index ec56ff29aac4..60a604cc7647 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -2006,7 +2006,7 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) { int ret; u32 mii_adv; - struct phy_device *phydev = dev->net->phydev; + struct phy_device *phydev; phydev = phy_find_first(dev->mdiobus); if (!phydev) { -- cgit From 5e264e2b532966bfcfe8869a3fccc9876ec2122c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 1 Feb 2018 17:29:21 +0000 Subject: vmxnet3: remove redundant initialization of pointer 'rq' Pointer rq is being initialized but this value is never read, it is being updated inside a for-loop. Remove the initialization and move it into the scope of the for-loop. Cleans up clang warning: drivers/net/vmxnet3/vmxnet3_drv.c:2763:27: warning: Value stored to 'rq' during its initialization is never read Signed-off-by: Colin Ian King Acked-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index cf95290b160c..8b39c160743d 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2760,9 +2760,6 @@ static void vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter) { size_t sz, i, ring0_size, ring1_size, comp_size; - struct vmxnet3_rx_queue *rq = &adapter->rx_queue[0]; - - if (adapter->netdev->mtu <= VMXNET3_MAX_SKB_BUF_SIZE - VMXNET3_MAX_ETH_HDR_SIZE) { adapter->skb_buf_size = adapter->netdev->mtu + @@ -2794,7 +2791,8 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter) comp_size = ring0_size + ring1_size; for (i = 0; i < adapter->num_rx_queues; i++) { - rq = &adapter->rx_queue[i]; + struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i]; + rq->rx_ring[0].size = ring0_size; rq->rx_ring[1].size = ring1_size; rq->comp_ring.size = comp_size; -- cgit From a107311d7fdf6b826f3737c4a90fd0e0046e7a3a Mon Sep 17 00:00:00 2001 From: Desnes Augusto Nunes do Rosario Date: Thu, 1 Feb 2018 16:04:30 -0200 Subject: ibmvnic: fix firmware version when no firmware level has been provided by the VIOS server Older versions of VIOS servers do not send the firmware level in the VPD buffer for the ibmvnic driver. Thus, not only the current message is mis- leading but the firmware version in the ethtool will be NULL. Therefore, this patch fixes the firmware string and its warning. Fixes: 4e6759be28e4 ("ibmvnic: Feature implementation of VPD for the ibmvnic driver") Signed-off-by: Desnes A. Nunes do Rosario Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 8c3058d5d191..7f0bea2104ab 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3305,7 +3305,11 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq, */ substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len); if (!substr) { - dev_info(dev, "No FW level provided by VPD\n"); + dev_info(dev, "Warning - No FW level has been provided in the VPD buffer by the VIOS Server\n"); + ptr = strncpy((char *)adapter->fw_version, "N/A", + 3 * sizeof(char)); + if (!ptr) + dev_err(dev, "Failed to inform that firmware version is unavailable to the adapter\n"); goto complete; } -- cgit From 743ffffefac1c670c6618742c923f6275d819604 Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Thu, 1 Feb 2018 22:45:17 +0300 Subject: net: pxa168_eth: add netconsole support This implements ndo_poll_controller callback which is necessary to enable netconsole. Signed-off-by: Alexander Monakov Cc: Russell King Cc: Sebastian Hesselbarth Cc: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/pxa168_eth.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 7bbd86f08e5f..3a9730612a70 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1362,6 +1362,15 @@ static int pxa168_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, return -EOPNOTSUPP; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void pxa168_eth_netpoll(struct net_device *dev) +{ + disable_irq(dev->irq); + pxa168_eth_int_handler(dev->irq, dev); + enable_irq(dev->irq); +} +#endif + static void pxa168_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -1390,6 +1399,9 @@ static const struct net_device_ops pxa168_eth_netdev_ops = { .ndo_do_ioctl = pxa168_eth_do_ioctl, .ndo_change_mtu = pxa168_eth_change_mtu, .ndo_tx_timeout = pxa168_eth_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = pxa168_eth_netpoll, +#endif }; static int pxa168_eth_probe(struct platform_device *pdev) -- cgit From 1d51877578799bfe0fcfe189d8233c9fccf05931 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 16:03:04 +0100 Subject: block: skd: fix incorrect linux/slab_def.h inclusion skd includes slab_def.h to get access to the slab cache object size. However, including this header breaks when we use SLUB or SLOB instead of the SLAB allocator, since the structure layout is completely different, as shown by this warning when we build this driver in one of the invalid configurations with link-time optimizations enabled: include/linux/slab.h:715:0: error: type of 'kmem_cache_size' does not match original declaration [-Werror=lto-type-mismatch] unsigned int kmem_cache_size(struct kmem_cache *s); mm/slab_common.c:77:14: note: 'kmem_cache_size' was previously declared here unsigned int kmem_cache_size(struct kmem_cache *s) ^ mm/slab_common.c:77:14: note: code may be misoptimized unless -fno-strict-aliasing is used include/linux/slab.h:147:0: error: type of 'kmem_cache_destroy' does not match original declaration [-Werror=lto-type-mismatch] void kmem_cache_destroy(struct kmem_cache *); mm/slab_common.c:858:6: note: 'kmem_cache_destroy' was previously declared here void kmem_cache_destroy(struct kmem_cache *s) ^ mm/slab_common.c:858:6: note: code may be misoptimized unless -fno-strict-aliasing is used include/linux/slab.h:140:0: error: type of 'kmem_cache_create' does not match original declaration [-Werror=lto-type-mismatch] struct kmem_cache *kmem_cache_create(const char *name, size_t size, mm/slab_common.c:534:1: note: 'kmem_cache_create' was previously declared here kmem_cache_create(const char *name, size_t size, size_t align, ^ This removes the header inclusion and instead uses the kmem_cache_size() interface to get the size in a reliable way. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index de0d08133c7e..e41935ab41ef 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -2603,7 +2602,8 @@ static void *skd_alloc_dma(struct skd_device *skdev, struct kmem_cache *s, buf = kmem_cache_alloc(s, gfp); if (!buf) return NULL; - *dma_handle = dma_map_single(dev, buf, s->size, dir); + *dma_handle = dma_map_single(dev, buf, + kmem_cache_size(s), dir); if (dma_mapping_error(dev, *dma_handle)) { kmem_cache_free(s, buf); buf = NULL; @@ -2618,7 +2618,8 @@ static void skd_free_dma(struct skd_device *skdev, struct kmem_cache *s, if (!vaddr) return; - dma_unmap_single(&skdev->pdev->dev, dma_handle, s->size, dir); + dma_unmap_single(&skdev->pdev->dev, dma_handle, + kmem_cache_size(s), dir); kmem_cache_free(s, vaddr); } -- cgit From 1d8ef0c07664dc48f2ff19a90b62dd3f6f425547 Mon Sep 17 00:00:00 2001 From: Edwin Peer Date: Thu, 1 Feb 2018 19:41:43 -0800 Subject: nfp: fix TLV offset calculation The data pointer in the config space TLV parser already includes NFP_NET_CFG_TLV_BASE, it should not be added again. Incorrect offset values were only used in printed user output, rendering the bug merely cosmetic. Fixes: 73a0329b057e ("nfp: add TLV capabilities to the BAR") Signed-off-by: Edwin Peer Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c index ffb402746ad4..1f9149bb2ae6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c @@ -65,7 +65,7 @@ int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem, u32 hdr = readl(data); length = FIELD_GET(NFP_NET_CFG_TLV_HEADER_LENGTH, hdr); - offset = data - ctrl_mem + NFP_NET_CFG_TLV_BASE; + offset = data - ctrl_mem; /* Advance past the header */ data += 4; -- cgit From ea6499e160a74ea813e53e7bef2ccb22df1e4929 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Fri, 2 Feb 2018 16:43:35 +0800 Subject: r8152: fix wrong checksum status for received IPv4 packets The device could only check the checksum of TCP and UDP packets. Therefore, for the IPv4 packets excluding TCP and UDP, the check of checksum is necessary, even though the IP checksum is correct. Take ICMP for example, The IP checksum may be correct, but the ICMP checksum may be wrong. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0657203ffb91..756de9ea8d2e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1848,11 +1848,9 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) if (opts2 & RD_IPV4_CS) { if (opts3 & IPF) checksum = CHECKSUM_NONE; - else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF)) - checksum = CHECKSUM_NONE; - else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF)) - checksum = CHECKSUM_NONE; - else + else if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) + checksum = CHECKSUM_UNNECESSARY; + else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF)) checksum = CHECKSUM_UNNECESSARY; } else if (opts2 & RD_IPV6_CS) { if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) -- cgit From aece4770fba62102951891c2f349a255c83eacb9 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Fri, 2 Feb 2018 16:43:36 +0800 Subject: r8152: set rx mode early when linking on Set rx mode before calling netif_wake_queue() when linking on to avoid the device missing the receiving packets. The transmission may start after calling netif_wake_queue(), and the packets of resopnse may reach before calling rtl8152_set_rx_mode() which let the device could receive packets. Then, the packets of response would be missed. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 756de9ea8d2e..958b2e8b90f6 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3795,11 +3795,12 @@ static void set_carrier(struct r8152 *tp) if (speed & LINK_STATUS) { if (!netif_carrier_ok(netdev)) { tp->rtl_ops.enable(tp); - set_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_stop_queue(netdev); napi_disable(napi); netif_carrier_on(netdev); rtl_start_rx(tp); + clear_bit(RTL8152_SET_RX_MODE, &tp->flags); + _rtl8152_set_rx_mode(netdev); napi_enable(&tp->napi); netif_wake_queue(netdev); netif_info(tp, link, netdev, "carrier on\n"); @@ -4259,7 +4260,7 @@ static int rtl8152_post_reset(struct usb_interface *intf) mutex_lock(&tp->control); tp->rtl_ops.enable(tp); rtl_start_rx(tp); - rtl8152_set_rx_mode(netdev); + _rtl8152_set_rx_mode(netdev); mutex_unlock(&tp->control); } -- cgit From 1a91649fd35ff53a646981e212496f1ae92a8487 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 16:18:37 +0100 Subject: net: cxgb4: avoid memcpy beyond end of source buffer Building with link-time-optimizations revealed that the cxgb4 driver does a fixed-size memcpy() from a variable-length constant string into the network interface name: In function 'memcpy', inlined from 'cfg_queues_uld.constprop' at drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c:335:2, inlined from 'cxgb4_register_uld.constprop' at drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c:719:9: include/linux/string.h:350:3: error: call to '__read_overflow2' declared with attribute error: detected read beyond size of object passed as 2nd parameter __read_overflow2(); ^ I can see two equally workable solutions: either we use a strncpy() instead of the memcpy() to stop at the end of the input, or we make the source buffer fixed length as well. This implements the latter. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 1d37672902da..a14e8db51cdc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -355,7 +355,7 @@ struct cxgb4_lld_info { }; struct cxgb4_uld_info { - const char *name; + char name[IFNAMSIZ]; void *handle; unsigned int nrxq; unsigned int rxq_size; -- cgit From 11f711081af0eb54190dc0de96ba4a9cd494666b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 16:44:47 +0100 Subject: net: qed: use correct strncpy() size passing the strlen() of the source string as the destination length is pointless, and gcc-8 now warns about it: drivers/net/ethernet/qlogic/qed/qed_debug.c: In function 'qed_grc_dump': include/linux/string.h:253: error: 'strncpy' specified bound depends on the length of the source argument [-Werror=stringop-overflow=] This changes qed_grc_dump_big_ram() to instead uses the length of the destination buffer, and use strscpy() to guarantee nul-termination. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index f2633ec87a6a..fdf37abee3d3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -3649,10 +3649,8 @@ static u32 qed_grc_dump_big_ram(struct qed_hwfn *p_hwfn, BIT(big_ram->is_256b_bit_offset[dev_data->chip_id]) ? 256 : 128; - strncpy(type_name, big_ram->instance_name, - strlen(big_ram->instance_name)); - strncpy(mem_name, big_ram->instance_name, - strlen(big_ram->instance_name)); + strscpy(type_name, big_ram->instance_name, sizeof(type_name)); + strscpy(mem_name, big_ram->instance_name, sizeof(mem_name)); /* Dump memory header */ offset += qed_grc_dump_mem_hdr(p_hwfn, -- cgit From cfabb1779d725c6d719793e44f5c50382eae6227 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 16:45:44 +0100 Subject: net: qlge: use memmove instead of skb_copy_to_linear_data gcc-8 points out that the skb_copy_to_linear_data() argument points to the skb itself, which makes it run into a problem with overlapping memcpy arguments: In file included from include/linux/ip.h:20, from drivers/net/ethernet/qlogic/qlge/qlge_main.c:26: drivers/net/ethernet/qlogic/qlge/qlge_main.c: In function 'ql_realign_skb': include/linux/skbuff.h:3378:2: error: 'memcpy' source argument is the same as destination [-Werror=restrict] memcpy(skb->data, from, len); It's unclear to me what the best solution is, maybe it ought to use a different helper that adjusts the skb data in a safe way. Simply using memmove() here seems like the easiest workaround. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 7b97a9969046..50038d946ced 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -1747,8 +1747,7 @@ static void ql_realign_skb(struct sk_buff *skb, int len) */ skb->data -= QLGE_SB_PAD - NET_IP_ALIGN; skb->tail -= QLGE_SB_PAD - NET_IP_ALIGN; - skb_copy_to_linear_data(skb, temp_addr, - (unsigned int)len); + memmove(skb->data, temp_addr, len); } /* -- cgit From 8cf4e6a04f734e831c2ac7f405071d1cde690ba8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 3 Feb 2018 11:25:20 +0100 Subject: firmware: dmi: Optimize dmi_matches Function dmi_matches can me made a bit faster: * The documented purpose of dmi_initialized is to catch too early calls to dmi_check_system(). I'm not fully convinced it justifies slowing down the initialization of all systems out there, but at least the check should not have been moved from dmi_check_system() to dmi_matches(). dmi_matches() is being called for every entry of the table passed to dmi_check_system(), causing the same redundant check to be performed again and again. So move it back to dmi_check_system(), reverting this specific portion of commit d7b1956fed33 ("DMI: Introduce dmi_first_match to make the interface more flexible"). * Don't check for the exact_match flag again when we already know its value. Signed-off-by: Jean Delvare Fixes: d7b1956fed33 ("DMI: Introduce dmi_first_match to make the interface more flexible") Cc: Jani Nikula Cc: Daniel Vetter Cc: Rafael J. Wysocki Cc: Jeff Garzik --- drivers/firmware/dmi_scan.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 783041964439..84356d86f359 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -784,19 +784,20 @@ static bool dmi_matches(const struct dmi_system_id *dmi) { int i; - WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); - for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { int s = dmi->matches[i].slot; if (s == DMI_NONE) break; if (dmi_ident[s]) { - if (!dmi->matches[i].exact_match && - strstr(dmi_ident[s], dmi->matches[i].substr)) - continue; - else if (dmi->matches[i].exact_match && - !strcmp(dmi_ident[s], dmi->matches[i].substr)) - continue; + if (dmi->matches[i].exact_match) { + if (!strcmp(dmi_ident[s], + dmi->matches[i].substr)) + continue; + } else { + if (strstr(dmi_ident[s], + dmi->matches[i].substr)) + continue; + } } /* No match */ @@ -832,6 +833,8 @@ int dmi_check_system(const struct dmi_system_id *list) int count = 0; const struct dmi_system_id *d; + WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); + for (d = list; !dmi_is_end_of_table(d); d++) if (dmi_matches(d)) { count++; -- cgit From 7117794feb1602ea5efca1c7bfd5b78c3278d29d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 3 Feb 2018 11:25:20 +0100 Subject: firmware: dmi_scan: Drop dmi_initialized I don't think it makes sense to check for a possible bad initialization order at run time on every system when it is all decided at build time. A more efficient way to make sure developers do not introduce new calls to dmi_check_system() too early in the initialization sequence is to simply document the expected call order. That way, developers have a chance to get it right immediately, without having to test-boot their kernel, wonder why it does not work, and parse the kernel logs for a warning message. And we get rid of the run-time performance penalty as a nice side effect. Signed-off-by: Jean Delvare Cc: Ingo Molnar --- drivers/firmware/dmi_scan.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 84356d86f359..8cd5db6691b2 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -26,11 +26,6 @@ static u16 dmi_num; static u8 smbios_entry_point[32]; static int smbios_entry_point_size; -/* - * Catch too early calls to dmi_check_system(): - */ -static int dmi_initialized; - /* DMI system identification string used during boot */ static char dmi_ids_string[128] __initdata; @@ -633,7 +628,7 @@ void __init dmi_scan_machine(void) if (!dmi_smbios3_present(buf)) { dmi_available = 1; - goto out; + return; } } if (efi.smbios == EFI_INVALID_TABLE_ADDR) @@ -651,7 +646,7 @@ void __init dmi_scan_machine(void) if (!dmi_present(buf)) { dmi_available = 1; - goto out; + return; } } else if (IS_ENABLED(CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK)) { p = dmi_early_remap(0xF0000, 0x10000); @@ -668,7 +663,7 @@ void __init dmi_scan_machine(void) if (!dmi_smbios3_present(buf)) { dmi_available = 1; dmi_early_unmap(p, 0x10000); - goto out; + return; } memcpy(buf, buf + 16, 16); } @@ -686,7 +681,7 @@ void __init dmi_scan_machine(void) if (!dmi_present(buf)) { dmi_available = 1; dmi_early_unmap(p, 0x10000); - goto out; + return; } memcpy(buf, buf + 16, 16); } @@ -694,8 +689,6 @@ void __init dmi_scan_machine(void) } error: pr_info("DMI not present or invalid.\n"); - out: - dmi_initialized = 1; } static ssize_t raw_table_read(struct file *file, struct kobject *kobj, @@ -827,14 +820,14 @@ static bool dmi_is_end_of_table(const struct dmi_system_id *dmi) * Walk the blacklist table running matching functions until someone * returns non zero or we hit the end. Callback function is called for * each successful match. Returns the number of matches. + * + * dmi_scan_machine must be called before this function is called. */ int dmi_check_system(const struct dmi_system_id *list) { int count = 0; const struct dmi_system_id *d; - WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); - for (d = list; !dmi_is_end_of_table(d); d++) if (dmi_matches(d)) { count++; @@ -857,6 +850,8 @@ EXPORT_SYMBOL(dmi_check_system); * * Walk the blacklist table until the first match is found. Return the * pointer to the matching entry or NULL if there's no match. + * + * dmi_scan_machine must be called before this function is called. */ const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) { -- cgit From a7770ae194569e96a93c48aceb304edded9cc648 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 3 Feb 2018 11:25:20 +0100 Subject: firmware: dmi_scan: Fix handling of empty DMI strings The handling of empty DMI strings looks quite broken to me: * Strings from 1 to 7 spaces are not considered empty. * True empty DMI strings (string index set to 0) are not considered empty, and result in allocating a 0-char string. * Strings with invalid index also result in allocating a 0-char string. * Strings starting with 8 spaces are all considered empty, even if non-space characters follow (sounds like a weird thing to do, but I have actually seen occurrences of this in DMI tables before.) * Strings which are considered empty are reported as 8 spaces, instead of being actually empty. Some of these issues are the result of an off-by-one error in memcmp, the rest is incorrect by design. So let's get it square: missing strings and strings made of only spaces, regardless of their length, should be treated as empty and no memory should be allocated for them. All other strings are non-empty and should be allocated. Signed-off-by: Jean Delvare Fixes: 79da4721117f ("x86: fix DMI out of memory problems") Cc: Parag Warudkar Cc: Ingo Molnar Cc: Thomas Gleixner --- drivers/firmware/dmi_scan.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 8cd5db6691b2..a7072e7880ee 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -18,7 +18,7 @@ EXPORT_SYMBOL_GPL(dmi_kobj); * of and an antecedent to, SMBIOS, which stands for System * Management BIOS. See further: http://www.dmtf.org/standards */ -static const char dmi_empty_string[] = " "; +static const char dmi_empty_string[] = ""; static u32 dmi_ver __initdata; static u32 dmi_len; @@ -39,25 +39,21 @@ static int dmi_memdev_nr; static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) { const u8 *bp = ((u8 *) dm) + dm->length; + const u8 *nsp; if (s) { - s--; - while (s > 0 && *bp) { + while (--s > 0 && *bp) bp += strlen(bp) + 1; - s--; - } - - if (*bp != 0) { - size_t len = strlen(bp)+1; - size_t cmp_len = len > 8 ? 8 : len; - if (!memcmp(bp, dmi_empty_string, cmp_len)) - return dmi_empty_string; + /* Strings containing only spaces are considered empty */ + nsp = bp; + while (*nsp == ' ') + nsp++; + if (*nsp != '\0') return bp; - } } - return ""; + return dmi_empty_string; } static const char * __init dmi_string(const struct dmi_header *dm, u8 s) -- cgit From a81114d03e4a529c4b68293249f75438b3c1783f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Sat, 3 Feb 2018 11:25:20 +0100 Subject: firmware: dmi: handle missing DMI data gracefully MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when booting a kernel with DMI support on a platform that has no DMI tables, the following output is emitted into the kernel log: [ 0.128818] DMI not present or invalid. ... [ 1.306659] dmi: Firmware registration failed. ... [ 2.908681] dmi-sysfs: dmi entry is absent. The first one is a pr_info(), but the subsequent ones are pr_err()s that complain about a condition that is not really an error to begin with. So let's clean this up, and give up silently if dma_available is not set. Signed-off-by: Ard Biesheuvel Acked-by: Martin Hundebøll Signed-off-by: Jean Delvare --- drivers/firmware/dmi-sysfs.c | 2 +- drivers/firmware/dmi_scan.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c index d5de6ee8466d..ecf2eeb5f6f9 100644 --- a/drivers/firmware/dmi-sysfs.c +++ b/drivers/firmware/dmi-sysfs.c @@ -652,7 +652,7 @@ static int __init dmi_sysfs_init(void) int val; if (!dmi_kobj) { - pr_err("dmi-sysfs: dmi entry is absent.\n"); + pr_debug("dmi-sysfs: dmi entry is absent.\n"); error = -ENODATA; goto err; } diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index a7072e7880ee..e763e1484331 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -704,10 +704,8 @@ static int __init dmi_init(void) u8 *dmi_table; int ret = -ENOMEM; - if (!dmi_available) { - ret = -ENODATA; - goto err; - } + if (!dmi_available) + return 0; /* * Set up dmi directory at /sys/firmware/dmi. This entry should stay -- cgit From c6a8b171ca8e338a3012420041346f0e50f7f649 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Tue, 5 Dec 2017 17:46:56 +0200 Subject: mailbox: qcom: Convert APCS IPC driver to use regmap This hardware block provides more functionalities that just IPC. Convert it to regmap to allow other child platform devices to use the same regmap. Signed-off-by: Georgi Djakov Acked-by: Bjorn Andersson Signed-off-by: Jassi Brar --- drivers/mailbox/qcom-apcs-ipc-mailbox.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index 9924c6d7f05d..ab344bc6fa63 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #define QCOM_APCS_IPC_BITS 32 @@ -26,19 +27,25 @@ struct qcom_apcs_ipc { struct mbox_controller mbox; struct mbox_chan mbox_chans[QCOM_APCS_IPC_BITS]; - void __iomem *reg; + struct regmap *regmap; unsigned long offset; }; +static const struct regmap_config apcs_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1000, + .fast_io = true, +}; + static int qcom_apcs_ipc_send_data(struct mbox_chan *chan, void *data) { struct qcom_apcs_ipc *apcs = container_of(chan->mbox, struct qcom_apcs_ipc, mbox); unsigned long idx = (unsigned long)chan->con_priv; - writel(BIT(idx), apcs->reg); - - return 0; + return regmap_write(apcs->regmap, apcs->offset, BIT(idx)); } static const struct mbox_chan_ops qcom_apcs_ipc_ops = { @@ -47,7 +54,9 @@ static const struct mbox_chan_ops qcom_apcs_ipc_ops = { static int qcom_apcs_ipc_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct qcom_apcs_ipc *apcs; + struct regmap *regmap; struct resource *res; unsigned long offset; void __iomem *base; @@ -63,9 +72,14 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + regmap = devm_regmap_init_mmio(&pdev->dev, base, &apcs_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + offset = (unsigned long)of_device_get_match_data(&pdev->dev); - apcs->reg = base + offset; + apcs->regmap = regmap; + apcs->offset = offset; /* Initialize channel identifiers */ for (i = 0; i < ARRAY_SIZE(apcs->mbox_chans); i++) -- cgit From c815d769b598196bdbd104a7e049d07ae6fba0d2 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Tue, 5 Dec 2017 17:46:57 +0200 Subject: mailbox: qcom: Create APCS child device for clock controller There is a clock controller functionality provided by the APCS hardware block of msm8916 devices. The device-tree would represent an APCS node with both mailbox and clock provider properties. Create a platform child device for the clock controller functionality so the driver can probe and use APCS as parent. Signed-off-by: Georgi Djakov Acked-by: Bjorn Andersson Signed-off-by: Jassi Brar --- drivers/mailbox/qcom-apcs-ipc-mailbox.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index ab344bc6fa63..57bde0dfd12f 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -29,6 +29,7 @@ struct qcom_apcs_ipc { struct regmap *regmap; unsigned long offset; + struct platform_device *clk; }; static const struct regmap_config apcs_regmap_config = { @@ -96,6 +97,14 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev) return ret; } + if (of_device_is_compatible(np, "qcom,msm8916-apcs-kpss-global")) { + apcs->clk = platform_device_register_data(&pdev->dev, + "qcom-apcs-msm8916-clk", + -1, NULL, 0); + if (IS_ERR(apcs->clk)) + dev_err(&pdev->dev, "failed to register APCS clk\n"); + } + platform_set_drvdata(pdev, apcs); return 0; @@ -104,8 +113,10 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev) static int qcom_apcs_ipc_remove(struct platform_device *pdev) { struct qcom_apcs_ipc *apcs = platform_get_drvdata(pdev); + struct platform_device *clk = apcs->clk; mbox_controller_unregister(&apcs->mbox); + platform_device_unregister(clk); return 0; } -- cgit