提交 76b17e6e 编写于 作者: J Julius Werner 提交者: Mark Brown

spi/rockchip: Add device tree property to configure Rx Sample Delay

We have found that we can sometimes see read failures on boards with
high-capacitance SPI lines. It seems that the controller samples the Rx
data line too early, and its register interface has an "Rx Sample Delay"
setting to fine-tune against this issue.

This patch adds a new optional device tree entry that can configure this
delay in terms of nanoseconds. The kernel will calculate the
best-fitting amount of parent clock ticks to program the controller with
based on that.
Signed-off-by: NJulius Werner <jwerner@chromium.org>
Signed-off-by: NMark Brown <broonie@kernel.org>
上级 2291793c
...@@ -24,6 +24,9 @@ Optional Properties: ...@@ -24,6 +24,9 @@ Optional Properties:
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, - dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt Documentation/devicetree/bindings/dma/dma.txt
- dma-names: DMA request names should include "tx" and "rx" if present. - dma-names: DMA request names should include "tx" and "rx" if present.
- rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling
Rx data (may need to be fine tuned for high capacitance lines).
No delay (0) by default.
Example: Example:
...@@ -33,6 +36,7 @@ Example: ...@@ -33,6 +36,7 @@ Example:
reg = <0xff110000 0x1000>; reg = <0xff110000 0x1000>;
dmas = <&pdma1 11>, <&pdma1 12>; dmas = <&pdma1 11>, <&pdma1 12>;
dma-names = "tx", "rx"; dma-names = "tx", "rx";
rx-sample-delay-ns = <10>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
......
...@@ -179,6 +179,7 @@ struct rockchip_spi { ...@@ -179,6 +179,7 @@ struct rockchip_spi {
u8 tmode; u8 tmode;
u8 bpw; u8 bpw;
u8 n_bytes; u8 n_bytes;
u8 rsd_nsecs;
unsigned len; unsigned len;
u32 speed; u32 speed;
...@@ -499,6 +500,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs) ...@@ -499,6 +500,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
{ {
u32 div = 0; u32 div = 0;
u32 dmacr = 0; u32 dmacr = 0;
int rsd = 0;
u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET) u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
| (CR0_SSD_ONE << CR0_SSD_OFFSET); | (CR0_SSD_ONE << CR0_SSD_OFFSET);
...@@ -528,6 +530,20 @@ static void rockchip_spi_config(struct rockchip_spi *rs) ...@@ -528,6 +530,20 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
div = max_t(u32, rs->max_freq / rs->speed, 1); div = max_t(u32, rs->max_freq / rs->speed, 1);
div = (div + 1) & 0xfffe; div = (div + 1) & 0xfffe;
/* Rx sample delay is expressed in parent clock cycles (max 3) */
rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->max_freq >> 8),
1000000000 >> 8);
if (!rsd && rs->rsd_nsecs) {
pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
rs->max_freq, rs->rsd_nsecs);
} else if (rsd > 3) {
rsd = 3;
pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
rs->max_freq, rs->rsd_nsecs,
rsd * 1000000000U / rs->max_freq);
}
cr0 |= rsd << CR0_RSD_OFFSET;
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
...@@ -620,6 +636,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -620,6 +636,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
struct rockchip_spi *rs; struct rockchip_spi *rs;
struct spi_master *master; struct spi_master *master;
struct resource *mem; struct resource *mem;
u32 rsd_nsecs;
master = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi)); master = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi));
if (!master) if (!master)
...@@ -671,6 +688,10 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -671,6 +688,10 @@ static int rockchip_spi_probe(struct platform_device *pdev)
rs->dev = &pdev->dev; rs->dev = &pdev->dev;
rs->max_freq = clk_get_rate(rs->spiclk); rs->max_freq = clk_get_rate(rs->spiclk);
if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
&rsd_nsecs))
rs->rsd_nsecs = rsd_nsecs;
rs->fifo_len = get_fifo_len(rs); rs->fifo_len = get_fifo_len(rs);
if (!rs->fifo_len) { if (!rs->fifo_len) {
dev_err(&pdev->dev, "Failed to get fifo length\n"); dev_err(&pdev->dev, "Failed to get fifo length\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册