Re: [PATCH v2 3/3] spi: meson-axg: add a linear clock divider support
Hi Jerome, On 2018/12/13 17:28, Jerome Brunet wrote: On Thu, 2018-12-13 at 09:55 +0100, Neil Armstrong wrote: diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig config SPI_MESON_SPICC tristate "Amlogic Meson SPICC controller" - depends on ARCH_MESON || COMPILE_TEST + depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST) The purpose of this patch is clock, right ? Why does it add a dependency on OF ? I did it by the way. Maybe it's better to add it in patch 1. +static int meson_spicc_clk_init(struct meson_spicc_device *spicc) +{ + struct device *dev = &spicc->pdev->dev; + struct clk_fixed_factor *div0; + struct clk_divider *div1; Could you come up with something better than div0 and div1 ? it is confusing, especially with the comment above about div3 and 4 ... fixed_factor, div maybe ? Good, It is really confusing, I will change next patch. + div1 = &meson_spicc_div1; + div1->reg = spicc->base + (u64)div1->reg; So you have static data which you override here. This works only if there is a single instance ... and does not really improve readability in your case. IMO, you'd be better off without the static data above. This is a terrible bug for more than one instances. I must overwrite it. + if (!spicc->data->has_enhance_clk_div) { Do all SoC with 'has_oen' have 'has_enhance_clk_div' too ? DO you really need two flags ? Yes, all Soc with 'has_oen' must have 'has_enhance_clk_div' too. It is distinct to use two flags here, what do you think of it? + mux = &meson_spicc_sel; + snprintf(name, sizeof(name), "%s#_sel", dev_name(dev)); + init.name = name; + init.ops = &clk_mux_ops; + init.parent_names = mux_parent_names; + init.num_parents = 2; + init.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT; Why CLK_SET_RATE_NO_REPARENT ? CCF should pick the parent that give the best results, best to let it do its task ... There are two div in AXG, one is the coarse old-div and the other is enhance-div. From SoCs designer's opinion, the ehance-div aims to take place of the old-div.
Re: [PATCH v2 2/3] spi: meson-axg: enhance output enable feature
Hi Jerome, On 2018/12/13 17:04, Jerome Brunet wrote: On Thu, 2018-12-13 at 16:39 +0800, Sunny Luo wrote: The SPICC controller in Meson-AXG is capable of driving the CLK/MOSI/SS signal lines through the idle state (between two transmission operation), which avoid the signals floating in unexpected state. @@ -453,6 +474,8 @@ static int meson_spicc_prepare_message(struct spi_master *master, writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG); + meson_spicc_oen_enable(spicc); + Any specific reason for doing this in prepare_message() ? It looks like something that could/should be done during the probe Yes, as replied in Mark's mail, i will move it into probe next patch.
Re: [PATCH v2 3/3] spi: meson-axg: add a linear clock divider support
Hi Neil, On 2018/12/13 16:55, Neil Armstrong wrote: Hi Sunny, On 13/12/2018 09:39, Sunny Luo wrote: The SPICC controller in Meson-AXG SoC is capable of using a linear clock divider to reach a much fine tuned range of clocks, while the old controller only use a power of two clock divider, result at a more coarse clock range. This patch should definitely go before patch 1. Would you please show the reason? + /* Set master mode and enable controller */ + writel_relaxed(SPICC_ENABLE | SPICC_MODE_MASTER, + spicc->base + SPICC_CONREG); Please remove it from meson_spicc_prepare_message() now. Yes, I moved it here and forgot remove it at prepare_message().
Re: [PATCH v2 2/3] spi: meson-axg: enhance output enable feature
Hi Neil, On 2018/12/13 16:53, Neil Armstrong wrote: Hi Sunny, On 13/12/2018 09:39, Sunny Luo wrote: The SPICC controller in Meson-AXG is capable of driving the CLK/MOSI/SS signal lines through the idle state (between two transmission operation), which avoid the signals floating in unexpected state. This is welcome, because it's really missing on GX... I tried implementing it with pinctrl at [1], but it's complex. Can you provide more info on how we should implement in on GX to be on par ? [1] https://github.com/superna/linux/commit/9c3a95659dd532d186556c1570c54d79ea5a4d45 GX is incapable of OEN. To be on par with it ,we have to pullup/down clk pin as you did at[1]. static const struct meson_spicc_data meson_spicc_gx_data = { - .max_speed_hz = 3000, + .max_speed_hz = 3000, Nitpick, but I would have kept the indentation here ... }; static const struct meson_spicc_data meson_spicc_axg_data = { - .max_speed_hz = 8000, + .max_speed_hz = 8000, + .has_oen= true, same here Anywy it's nitpick, ok, i will revert it next patch.
Re: [PATCH v2 2/3] spi: meson-axg: enhance output enable feature
Hi Mark&Jerome, On 2018/12/13 19:53, Mark Brown wrote: On Thu, Dec 13, 2018 at 10:04:56AM +0100, Jerome Brunet wrote: On Thu, 2018-12-13 at 16:39 +0800, Sunny Luo wrote: writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG); + meson_spicc_oen_enable(spicc); + Any specific reason for doing this in prepare_message() ? It looks like something that could/should be done during the probe ? If it's for power management then there should be a matching disable in unprepare_message() (or this should just be in the runtime PM code, though it's possible there's stuff that's only needed while actually doing transfers in which case this could make sense). OEN is only used to avoid the signals floating in unexpected state, i will move it into probe next patch. Please delete unneeded context from mails when replying. Doing this makes it much easier to find your reply in the message, helping ensure it won't be missed by people scrolling through the irrelevant quoted material. OK.
Re: [PATCH v2 1/3] spi: meson-axg: support MAX 80M clock
Hi Neil, On 2018/12/13 16:49, Neil Armstrong wrote: Hi Sunny, On 13/12/2018 09:39, Sunny Luo wrote: The SPICC controller in Meson-AXG is capable of running at 80M clock. The ASIC IP is improved and the clock is actually running higher than previous old SoCs. Signed-off-by: Sunny Luo Signed-off-by: Yixun Lan --- drivers/spi/spi-meson-spicc.c | 37 + 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 7fe4488..b56249d 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -9,11 +9,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -34,7 +36,6 @@ * to have a CS go down over the full transfer */ -#define SPICC_MAX_FREQ 3000 #define SPICC_MAX_BURST 128 /* Register Map */ @@ -120,6 +121,10 @@ #define SPICC_BURST_MAX 16 #define SPICC_FIFO_HALF 10 +struct meson_spicc_data { + unsigned intmax_speed_hz; +}; + struct meson_spicc_device { struct spi_master *master; struct platform_device *pdev; @@ -127,6 +132,7 @@ struct meson_spicc_device { struct clk *core; struct spi_message *message; struct spi_transfer *xfer; + const struct meson_spicc_data *data; u8 *tx_buf; u8 *rx_buf; unsigned intbytes_per_word; @@ -517,6 +523,9 @@ static int meson_spicc_probe(struct platform_device *pdev) spicc->pdev = pdev; platform_set_drvdata(pdev, spicc); + spicc->data = (const struct meson_spicc_data *) + of_device_get_match_data(&pdev->dev); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spicc->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(spicc->base)) { @@ -567,11 +576,9 @@ static int meson_spicc_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = meson_spicc_unprepare_transfer; master->transfer_one = meson_spicc_transfer_one; - /* Setup max rate according to the Meson GX datasheet */ - if ((rate >> 2) > SPICC_MAX_FREQ) - master->max_speed_hz = SPICC_MAX_FREQ; - else - master->max_speed_hz = rate >> 2; + /* Setup max rate according to the Meson datasheet */ + master->max_speed_hz = min_t(unsigned int, rate >> 1, +spicc->data->max_speed_hz); I think "rate >> 1" here depends on patch 3, either move patch 3 before this one or keep "rate >> 2" and change it back to "rate >> 1" on patch 3. Yes, this change should be in patch 3. ret = devm_spi_register_master(&pdev->dev, master); if (ret) { @@ -602,9 +609,23 @@ static int meson_spicc_remove(struct platform_device *pdev) return 0; } +static const struct meson_spicc_data meson_spicc_gx_data = { + .max_speed_hz = 3000, +}; + +static const struct meson_spicc_data meson_spicc_axg_data = { + .max_speed_hz = 8000, +}; + static const struct of_device_id meson_spicc_of_match[] = { - { .compatible = "amlogic,meson-gx-spicc", }, - { .compatible = "amlogic,meson-axg-spicc", }, + { + .compatible = "amlogic,meson-gx-spicc", + .data = &meson_spicc_gx_data, + }, + { + .compatible = "amlogic,meson-axg-spicc", + .data = &meson_spicc_axg_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, meson_spicc_of_match); .
[PATCH v2 2/3] spi: meson-axg: enhance output enable feature
The SPICC controller in Meson-AXG is capable of driving the CLK/MOSI/SS signal lines through the idle state (between two transmission operation), which avoid the signals floating in unexpected state. Signed-off-by: Sunny Luo Signed-off-by: Yixun Lan --- drivers/spi/spi-meson-spicc.c | 28 ++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index b56249d..0384c28 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -115,6 +115,13 @@ #define SPICC_DWADDR 0x24/* Write Address of DMA */ +#define SPICC_ENH_CTL0 0x38/* Enhanced Feature */ +#define SPICC_ENH_MOSI_OEN BIT(25) +#define SPICC_ENH_CLK_OEN BIT(26) +#define SPICC_ENH_CS_OEN BIT(27) +#define SPICC_ENH_CLK_CS_DELAY_EN BIT(28) +#define SPICC_ENH_MAIN_CLK_AO BIT(29) + #define writel_bits_relaxed(mask, val, addr) \ writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) @@ -123,6 +130,7 @@ struct meson_spicc_data { unsigned intmax_speed_hz; + boolhas_oen; }; struct meson_spicc_device { @@ -145,6 +153,19 @@ struct meson_spicc_device { boolis_last_burst; }; +static void meson_spicc_oen_enable(struct meson_spicc_device *spicc) +{ + u32 conf; + + if (!spicc->data->has_oen) + return; + + conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) | + SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN; + + writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0); +} + static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc) { return !!FIELD_GET(SPICC_TF, @@ -453,6 +474,8 @@ static int meson_spicc_prepare_message(struct spi_master *master, writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG); + meson_spicc_oen_enable(spicc); + return 0; } @@ -610,11 +633,12 @@ static int meson_spicc_remove(struct platform_device *pdev) } static const struct meson_spicc_data meson_spicc_gx_data = { - .max_speed_hz = 3000, + .max_speed_hz = 3000, }; static const struct meson_spicc_data meson_spicc_axg_data = { - .max_speed_hz = 8000, + .max_speed_hz = 8000, + .has_oen= true, }; static const struct of_device_id meson_spicc_of_match[] = { -- 2.7.4
[PATCH v2 3/3] spi: meson-axg: add a linear clock divider support
The SPICC controller in Meson-AXG SoC is capable of using a linear clock divider to reach a much fine tuned range of clocks, while the old controller only use a power of two clock divider, result at a more coarse clock range. Also convert the clock registration into Common Clock Framework. Signed-off-by: Sunny Luo Signed-off-by: Yixun Lan --- drivers/spi/Kconfig | 2 +- drivers/spi/spi-meson-spicc.c | 209 ++ 2 files changed, 170 insertions(+), 41 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9f89cb1..75f7362 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -384,7 +384,7 @@ config SPI_FSL_ESPI config SPI_MESON_SPICC tristate "Amlogic Meson SPICC controller" - depends on ARCH_MESON || COMPILE_TEST + depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST) help This enables master mode support for the SPICC (SPI communication controller) available in Amlogic Meson SoCs. diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 0384c28..59af18e 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -116,6 +116,9 @@ #define SPICC_DWADDR 0x24/* Write Address of DMA */ #define SPICC_ENH_CTL0 0x38/* Enhanced Feature */ +#define SPICC_ENH_CLK_CS_DELAY_MASKGENMASK(15, 0) +#define SPICC_ENH_DATARATE_MASKGENMASK(23, 16) +#define SPICC_ENH_DATARATE_EN BIT(24) #define SPICC_ENH_MOSI_OEN BIT(25) #define SPICC_ENH_CLK_OEN BIT(26) #define SPICC_ENH_CS_OEN BIT(27) @@ -131,6 +134,7 @@ struct meson_spicc_data { unsigned intmax_speed_hz; boolhas_oen; + boolhas_enhance_clk_div; }; struct meson_spicc_device { @@ -138,6 +142,7 @@ struct meson_spicc_device { struct platform_device *pdev; void __iomem*base; struct clk *core; + struct clk *clk; struct spi_message *message; struct spi_transfer *xfer; const struct meson_spicc_data *data; @@ -325,40 +330,6 @@ static irqreturn_t meson_spicc_irq(int irq, void *data) return IRQ_HANDLED; } -static u32 meson_spicc_setup_speed(struct meson_spicc_device *spicc, u32 conf, - u32 speed) -{ - unsigned long parent, value; - unsigned int i, div; - - parent = clk_get_rate(spicc->core); - - /* Find closest inferior/equal possible speed */ - for (i = 0 ; i < 7 ; ++i) { - /* 2^(data_rate+2) */ - value = parent >> (i + 2); - - if (value <= speed) - break; - } - - /* If provided speed it lower than max divider, use max divider */ - if (i > 7) { - div = 7; - dev_warn_once(&spicc->pdev->dev, "unable to get close to speed %u\n", - speed); - } else - div = i; - - dev_dbg(&spicc->pdev->dev, "parent %lu, speed %u -> %lu (%u)\n", - parent, speed, value, div); - - conf &= ~SPICC_DATARATE_MASK; - conf |= FIELD_PREP(SPICC_DATARATE_MASK, div); - - return conf; -} - static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, struct spi_transfer *xfer) { @@ -367,9 +338,6 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, /* Read original configuration */ conf = conf_orig = readl_relaxed(spicc->base + SPICC_CONREG); - /* Select closest divider */ - conf = meson_spicc_setup_speed(spicc, conf, xfer->speed_hz); - /* Setup word width */ conf &= ~SPICC_BITLENGTH_MASK; conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, @@ -378,6 +346,8 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, /* Ignore if unchanged */ if (conf != conf_orig) writel_relaxed(conf, spicc->base + SPICC_CONREG); + + clk_set_rate(spicc->clk, xfer->speed_hz); } static int meson_spicc_transfer_one(struct spi_master *master, @@ -486,9 +456,6 @@ static int meson_spicc_unprepare_transfer(struct spi_master *master) /* Disable all IRQs */ writel(0, spicc->base + SPICC_INTREG); - /* Disable controller */ - writel_bits_relaxed(SPICC_ENABLE, 0, spicc->base + SPICC_CONREG); - device_reset_optional(&spicc->pdev->dev); return 0; @@ -528,6 +495,157 @@ static void meson_spicc_cleanup(struct spi_device *spi) spi->controller_state = NULL; } +/* + * The Clock Mux + *x-x x
[PATCH v2 0/3] spi: meson-axg: add few enhanced features
add a few enhanced features for the SPICC controller of Meson-AXG SoC. These patches are actually quite independent from each other, I send them together in case to avoid the file conflicts. Changes since v1 at [1] - Add OF and COMMON_CLK dependence for SPICC in Kconfig to avoid compiling error. [1] https://lore.kernel.org/lkml/20180503213645.20694-1-yixun@amlogic.com Sunny Luo (3): spi: meson-axg: support MAX 80M clock spi: meson-axg: enhance output enable feature spi: meson-axg: add a linear clock divider support drivers/spi/Kconfig | 2 +- drivers/spi/spi-meson-spicc.c | 270 ++ 2 files changed, 223 insertions(+), 49 deletions(-) -- 2.7.4
[PATCH v2 1/3] spi: meson-axg: support MAX 80M clock
The SPICC controller in Meson-AXG is capable of running at 80M clock. The ASIC IP is improved and the clock is actually running higher than previous old SoCs. Signed-off-by: Sunny Luo Signed-off-by: Yixun Lan --- drivers/spi/spi-meson-spicc.c | 37 + 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 7fe4488..b56249d 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -9,11 +9,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -34,7 +36,6 @@ * to have a CS go down over the full transfer */ -#define SPICC_MAX_FREQ 3000 #define SPICC_MAX_BURST128 /* Register Map */ @@ -120,6 +121,10 @@ #define SPICC_BURST_MAX16 #define SPICC_FIFO_HALF 10 +struct meson_spicc_data { + unsigned intmax_speed_hz; +}; + struct meson_spicc_device { struct spi_master *master; struct platform_device *pdev; @@ -127,6 +132,7 @@ struct meson_spicc_device { struct clk *core; struct spi_message *message; struct spi_transfer *xfer; + const struct meson_spicc_data *data; u8 *tx_buf; u8 *rx_buf; unsigned intbytes_per_word; @@ -517,6 +523,9 @@ static int meson_spicc_probe(struct platform_device *pdev) spicc->pdev = pdev; platform_set_drvdata(pdev, spicc); + spicc->data = (const struct meson_spicc_data *) + of_device_get_match_data(&pdev->dev); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spicc->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(spicc->base)) { @@ -567,11 +576,9 @@ static int meson_spicc_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = meson_spicc_unprepare_transfer; master->transfer_one = meson_spicc_transfer_one; - /* Setup max rate according to the Meson GX datasheet */ - if ((rate >> 2) > SPICC_MAX_FREQ) - master->max_speed_hz = SPICC_MAX_FREQ; - else - master->max_speed_hz = rate >> 2; + /* Setup max rate according to the Meson datasheet */ + master->max_speed_hz = min_t(unsigned int, rate >> 1, +spicc->data->max_speed_hz); ret = devm_spi_register_master(&pdev->dev, master); if (ret) { @@ -602,9 +609,23 @@ static int meson_spicc_remove(struct platform_device *pdev) return 0; } +static const struct meson_spicc_data meson_spicc_gx_data = { + .max_speed_hz = 3000, +}; + +static const struct meson_spicc_data meson_spicc_axg_data = { + .max_speed_hz = 8000, +}; + static const struct of_device_id meson_spicc_of_match[] = { - { .compatible = "amlogic,meson-gx-spicc", }, - { .compatible = "amlogic,meson-axg-spicc", }, + { + .compatible = "amlogic,meson-gx-spicc", + .data = &meson_spicc_gx_data, + }, + { + .compatible = "amlogic,meson-axg-spicc", + .data = &meson_spicc_axg_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, meson_spicc_of_match); -- 2.7.4