Skip to content

Commit

Permalink
Merge tag 'spi-fix-v6.0-rc1' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "A few fixes that came in since my pull request, the Meson fix is a
  little large since it's fixing all possible cases of the problem that
  was observed with the driver and clock API trying to share
  configuration by integrating the device clocking fully with the clock
  API rather than spot fixing the one instance that was observed"

* tag 'spi-fix-v6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: dt-bindings: Drop Pratyush Yadav
  spi: meson-spicc: add local pow2 clock ops to preserve rate between messages
  MAINTAINERS: rectify entry for ARM/HPE GXP ARCHITECTURE
  spi: spi.c: Add missing __percpu annotations in users of spi_statistics
  • Loading branch information
torvalds committed Aug 16, 2022
2 parents 15df648 + 2fd92c7 commit 339800d
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description:
See spi-peripheral-props.yaml for more info.

maintainers:
- Pratyush Yadav <p.yadav@ti.com>
- Vaishnav Achath <vaishnav.a@ti.com>

properties:
# cdns,qspi-nor.yaml
Expand Down
2 changes: 1 addition & 1 deletion Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cadence Quad SPI controller

maintainers:
- Pratyush Yadav <p.yadav@ti.com>
- Vaishnav Achath <vaishnav.a@ti.com>

allOf:
- $ref: spi-controller.yaml#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ description:
their own separate schema that should be referenced from here.

maintainers:
- Pratyush Yadav <[email protected]>
- Mark Brown <[email protected]>

properties:
reg:
Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -2178,7 +2178,7 @@ M: Jean-Marie Verdun <[email protected]>
M: Nick Hawkins <[email protected]>
S: Maintained
F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml
F: Documentation/devicetree/bindings/spi/hpe,gxp-spi.yaml
F: Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml
F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
F: arch/arm/boot/dts/hpe-bmc*
F: arch/arm/boot/dts/hpe-gxp*
Expand Down
129 changes: 101 additions & 28 deletions drivers/spi/spi-meson-spicc.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ struct meson_spicc_device {
void __iomem *base;
struct clk *core;
struct clk *pclk;
struct clk_divider pow2_div;
struct clk *clk;
struct spi_message *message;
struct spi_transfer *xfer;
Expand All @@ -168,6 +169,8 @@ struct meson_spicc_device {
unsigned long xfer_remain;
};

#define pow2_clk_to_spicc(_div) container_of(_div, struct meson_spicc_device, pow2_div)

static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
{
u32 conf;
Expand Down Expand Up @@ -421,7 +424,7 @@ static int meson_spicc_prepare_message(struct spi_master *master,
{
struct meson_spicc_device *spicc = spi_master_get_devdata(master);
struct spi_device *spi = message->spi;
u32 conf = 0;
u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;

/* Store current message */
spicc->message = message;
Expand Down Expand Up @@ -458,8 +461,6 @@ static int meson_spicc_prepare_message(struct spi_master *master,
/* Select CS */
conf |= FIELD_PREP(SPICC_CS_MASK, spi->chip_select);

/* Default Clock rate core/4 */

/* Default 8bit word */
conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, 8 - 1);

Expand All @@ -476,12 +477,16 @@ static int meson_spicc_prepare_message(struct spi_master *master,
static int meson_spicc_unprepare_transfer(struct spi_master *master)
{
struct meson_spicc_device *spicc = spi_master_get_devdata(master);
u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;

/* Disable all IRQs */
writel(0, spicc->base + SPICC_INTREG);

device_reset_optional(&spicc->pdev->dev);

/* Set default configuration, keeping datarate field */
writel_relaxed(conf, spicc->base + SPICC_CONREG);

return 0;
}

Expand Down Expand Up @@ -518,14 +523,60 @@ static void meson_spicc_cleanup(struct spi_device *spi)
* Clk path for G12A series:
* pclk -> pow2 fixed div -> pow2 div -> mux -> out
* pclk -> enh fixed div -> enh div -> mux -> out
*
* The pow2 divider is tied to the controller HW state, and the
* divider is only valid when the controller is initialized.
*
* A set of clock ops is added to make sure we don't read/set this
* clock rate while the controller is in an unknown state.
*/

static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);

if (!spicc->master->cur_msg || !spicc->master->busy)
return 0;

return clk_divider_ops.recalc_rate(hw, parent_rate);
}

static int meson_spicc_pow2_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);

if (!spicc->master->cur_msg || !spicc->master->busy)
return -EINVAL;

return clk_divider_ops.determine_rate(hw, req);
}

static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);

if (!spicc->master->cur_msg || !spicc->master->busy)
return -EINVAL;

return clk_divider_ops.set_rate(hw, rate, parent_rate);
}

const struct clk_ops meson_spicc_pow2_clk_ops = {
.recalc_rate = meson_spicc_pow2_recalc_rate,
.determine_rate = meson_spicc_pow2_determine_rate,
.set_rate = meson_spicc_pow2_set_rate,
};

static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc)
{
struct device *dev = &spicc->pdev->dev;
struct clk_fixed_factor *pow2_fixed_div, *enh_fixed_div;
struct clk_divider *pow2_div, *enh_div;
struct clk_mux *mux;
struct clk_fixed_factor *pow2_fixed_div;
struct clk_init_data init;
struct clk *clk;
struct clk_parent_data parent_data[2];
Expand Down Expand Up @@ -560,31 +611,45 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
if (WARN_ON(IS_ERR(clk)))
return PTR_ERR(clk);

pow2_div = devm_kzalloc(dev, sizeof(*pow2_div), GFP_KERNEL);
if (!pow2_div)
return -ENOMEM;

snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev));
init.name = name;
init.ops = &clk_divider_ops;
init.flags = CLK_SET_RATE_PARENT;
init.ops = &meson_spicc_pow2_clk_ops;
/*
* Set NOCACHE here to make sure we read the actual HW value
* since we reset the HW after each transfer.
*/
init.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE;
parent_data[0].hw = &pow2_fixed_div->hw;
init.num_parents = 1;

pow2_div->shift = 16,
pow2_div->width = 3,
pow2_div->flags = CLK_DIVIDER_POWER_OF_TWO,
pow2_div->reg = spicc->base + SPICC_CONREG;
pow2_div->hw.init = &init;
spicc->pow2_div.shift = 16,
spicc->pow2_div.width = 3,
spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO,
spicc->pow2_div.reg = spicc->base + SPICC_CONREG;
spicc->pow2_div.hw.init = &init;

clk = devm_clk_register(dev, &pow2_div->hw);
if (WARN_ON(IS_ERR(clk)))
return PTR_ERR(clk);
spicc->clk = devm_clk_register(dev, &spicc->pow2_div.hw);
if (WARN_ON(IS_ERR(spicc->clk)))
return PTR_ERR(spicc->clk);

if (!spicc->data->has_enhance_clk_div) {
spicc->clk = clk;
return 0;
}
return 0;
}

static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
{
struct device *dev = &spicc->pdev->dev;
struct clk_fixed_factor *enh_fixed_div;
struct clk_divider *enh_div;
struct clk_mux *mux;
struct clk_init_data init;
struct clk *clk;
struct clk_parent_data parent_data[2];
char name[64];

memset(&init, 0, sizeof(init));
memset(&parent_data, 0, sizeof(parent_data));

init.parent_data = parent_data;

/* algorithm for enh div: rate = freq / 2 / (N + 1) */

Expand Down Expand Up @@ -637,7 +702,7 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
snprintf(name, sizeof(name), "%s#sel", dev_name(dev));
init.name = name;
init.ops = &clk_mux_ops;
parent_data[0].hw = &pow2_div->hw;
parent_data[0].hw = &spicc->pow2_div.hw;
parent_data[1].hw = &enh_div->hw;
init.num_parents = 2;
init.flags = CLK_SET_RATE_PARENT;
Expand Down Expand Up @@ -754,12 +819,20 @@ static int meson_spicc_probe(struct platform_device *pdev)

meson_spicc_oen_enable(spicc);

ret = meson_spicc_clk_init(spicc);
ret = meson_spicc_pow2_clk_init(spicc);
if (ret) {
dev_err(&pdev->dev, "clock registration failed\n");
dev_err(&pdev->dev, "pow2 clock registration failed\n");
goto out_clk;
}

if (spicc->data->has_enhance_clk_div) {
ret = meson_spicc_enh_clk_init(spicc);
if (ret) {
dev_err(&pdev->dev, "clock registration failed\n");
goto out_clk;
}
}

ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "spi master registration failed\n");
Expand Down
14 changes: 7 additions & 7 deletions drivers/spi/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static ssize_t driver_override_show(struct device *dev,
}
static DEVICE_ATTR_RW(driver_override);

static struct spi_statistics *spi_alloc_pcpu_stats(struct device *dev)
static struct spi_statistics __percpu *spi_alloc_pcpu_stats(struct device *dev)
{
struct spi_statistics __percpu *pcpu_stats;

Expand Down Expand Up @@ -162,7 +162,7 @@ static struct device_attribute dev_attr_spi_device_##field = { \
}

#define SPI_STATISTICS_SHOW_NAME(name, file, field) \
static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \
static ssize_t spi_statistics_##name##_show(struct spi_statistics __percpu *stat, \
char *buf) \
{ \
ssize_t len; \
Expand Down Expand Up @@ -309,7 +309,7 @@ static const struct attribute_group *spi_master_groups[] = {
NULL,
};

static void spi_statistics_add_transfer_stats(struct spi_statistics *pcpu_stats,
static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pcpu_stats,
struct spi_transfer *xfer,
struct spi_controller *ctlr)
{
Expand Down Expand Up @@ -1275,8 +1275,8 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
struct spi_message *msg,
struct spi_transfer *xfer)
{
struct spi_statistics *statm = ctlr->pcpu_statistics;
struct spi_statistics *stats = msg->spi->pcpu_statistics;
struct spi_statistics __percpu *statm = ctlr->pcpu_statistics;
struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics;
u32 speed_hz = xfer->speed_hz;
unsigned long long ms;

Expand Down Expand Up @@ -1432,8 +1432,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_transfer *xfer;
bool keep_cs = false;
int ret = 0;
struct spi_statistics *statm = ctlr->pcpu_statistics;
struct spi_statistics *stats = msg->spi->pcpu_statistics;
struct spi_statistics __percpu *statm = ctlr->pcpu_statistics;
struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics;

spi_set_cs(msg->spi, true, false);

Expand Down

0 comments on commit 339800d

Please sign in to comment.