[PATCH v2 2/2] mtd: spi-nor: add rockchip serial flash controller driver

Marek Vasut marek.vasut at gmail.com
Tue Nov 29 19:23:36 PST 2016


On 11/30/2016 02:17 AM, Shawn Lin wrote:
[...]
>>> +static inline int rockchip_sfc_pio_read(struct rockchip_sfc *sfc,
>>> u_char *buf,
>>> +                    size_t len)
>>> +{
>>> +    u32 dwords, rx_wl, count, i, tmp;
>>> +    unsigned long timeout;
>>> +    int ret = 0;
>>> +    u32 *tbuf = (u32 *)buf;
>>> +    u_char *tbuf2;
>>> +
>>> +    /*
>>> +     * Align bytes to dwords, and get the remained bytes.
>>> +     * We should always round down to DWORD as the ahb for
>>> +     * Rockchip Socs won't support non-aligned-to-DWORD transfer.
>>> +     * So please don't use any APIs that will finally use non-aligned
>>> +     * read, for instance, memcpy_fromio or ioread32_rep etc.
>>> +     */
>>> +    dwords = len >> 2;
>>> +    len = len & 0x3;
>>
>> Won't this overwrite some bits past the $buf if you write more than $len
>> bytes into this memory location ?
>>
> 
> I can't see the possibility here to overwrite $buf, no?

Looking at the code again, I believe not, although it's quite
non-trivial piece of code.

>>> +    while (dwords) {
>>> +        rx_wl = (readl_relaxed(sfc->regbase + SFC_FSR) >>
>>> +             SFC_FSR_RX_WATER_LVL_SHIFT) &
>>> +             SFC_FSR_RX_WATER_LVL_MASK;
>>> +
>>> +        if (rx_wl > 0) {
>>> +            count = min_t(u32, dwords, rx_wl);
>>> +            for (i = 0; i < count; i++) {
>>> +                *tbuf++ = readl_relaxed(sfc->regbase +
>>> +                            SFC_DATA);
>>> +                dwords--;
>>> +            }
>>> +
>>> +            if (dwords == 0)
>>> +                break;
>>> +            timeout = 0;
>>> +        } else {
>>> +            mdelay(1);
>>> +            if (timeout++ > SFC_MAX_IDLE_RETRY) {
>>> +                ret = -ETIMEDOUT;
>>> +                break;
>>> +            }
>>> +        }
>>> +    }
>>> +
>>> +    if (ret)
>>> +        return ret;
>>> +
>>> +    /* Read the remained bytes */
>>> +    timeout = 0;
>>> +    tbuf2 = (u_char *)tbuf;
>>> +    while (len) {
>>> +        rx_wl = (readl_relaxed(sfc->regbase + SFC_FSR) >>
>>> +             SFC_FSR_RX_WATER_LVL_SHIFT) &
>>> +             SFC_FSR_RX_WATER_LVL_MASK;
>>> +        if (rx_wl > 0) {
>>> +            tmp = readl_relaxed(sfc->regbase + SFC_DATA);
>>> +            for (i = 0; i < len; i++)
>>> +                tbuf2[i] = (u8)((tmp >> (i * 8)) & 0xff);
>>> +            goto done;
>>> +        } else {
>>> +            mdelay(1);
>>> +            if (timeout++ > SFC_MAX_IDLE_RETRY) {
>>> +                ret = -ETIMEDOUT;
>>> +                break;
>>> +            }
>>> +        }
>>> +    }

[...]

>>> +static int rockchip_sfc_probe(struct platform_device *pdev)
>>> +{
>>> +    struct device *dev = &pdev->dev;
>>> +    struct resource *res;
>>> +    struct rockchip_sfc *sfc;
>>> +    int ret;
>>> +
>>> +    sfc = devm_kzalloc(dev, sizeof(*sfc), GFP_KERNEL);
>>> +    if (!sfc)
>>> +        return -ENOMEM;
>>> +
>>> +    platform_set_drvdata(pdev, sfc);
>>> +    sfc->dev = dev;
>>> +
>>> +    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +    sfc->regbase = devm_ioremap_resource(dev, res);
>>> +    if (IS_ERR(sfc->regbase))
>>> +        return PTR_ERR(sfc->regbase);
>>> +
>>> +    sfc->clk = devm_clk_get(&pdev->dev, "sfc");
>>> +    if (IS_ERR(sfc->clk)) {
>>> +        dev_err(&pdev->dev, "Failed to get sfc interface clk\n");
>>> +        return PTR_ERR(sfc->clk);
>>> +    }
>>> +
>>> +    sfc->hclk = devm_clk_get(&pdev->dev, "hsfc");
>>> +    if (IS_ERR(sfc->hclk)) {
>>> +        dev_err(&pdev->dev, "Failed to get sfc ahp clk\n");
>>> +        return PTR_ERR(sfc->hclk);
>>> +    }
>>> +
>>> +    ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
>>> +    if (ret) {
>>> +        dev_warn(dev, "Unable to set dma mask\n");
>>> +        return ret;
>>> +    }
>>> +
>>> +    sfc->buffer = dmam_alloc_coherent(dev, SFC_DMA_MAX_LEN,
>>> +            &sfc->dma_buffer, GFP_KERNEL);
>>> +    if (!sfc->buffer)
>>> +        return -ENOMEM;
>>> +
>>> +    mutex_init(&sfc->lock);
>>> +
>>> +    ret = clk_prepare_enable(sfc->hclk);
>>> +    if (ret) {
>>> +        dev_err(&pdev->dev, "Failed to enable hclk\n");
>>> +        goto err_hclk;
>>> +    }
>>> +
>>> +    ret = clk_prepare_enable(sfc->clk);
>>> +    if (ret) {
>>> +        dev_err(&pdev->dev, "Failed to enable clk\n");
>>> +        goto err_clk;
>>> +    }
>>> +
>>> +    sfc->use_dma = !of_property_read_bool(sfc->dev->of_node,
>>> +                          "rockchip,sfc-no-dma");
>>> +
>>> +    sfc->negative_edge = of_device_is_compatible(sfc->dev->of_node,
>>> +                             "rockchip,rk1108-sfc");
>>
>> I think this should rather be a boolean property -- but isn't this
>> something like CPOL or CPHA anyway ?
> 
> It isn't the same as CPOL or CPHA. And this value should be Soc
> specificed.

So what is this about ? Can you explain what this negative_edge thing is
and how it works on the bus-level ?

[...]

-- 
Best regards,
Marek Vasut



More information about the linux-mtd mailing list