* Re: [PATCH v7 2/2] mtd: rawnand: meson: add support for Amlogic NAND flash controller
From: Miquel Raynal @ 2018-12-07 9:42 UTC (permalink / raw)
To: Jianxin Pan
Cc: Rob Herring, Hanjie Lin, Victor Wan, Marek Vasut,
Martin Blumenstingl, Richard Weinberger, Neil Armstrong,
Yixun Lan, linux-kernel, Boris Brezillon, Jian Hu, Liang Yang,
linux-mtd, Kevin Hilman, Carlo Caione, linux-amlogic,
Brian Norris, David Woodhouse, linux-arm-kernel, Jerome Brunet
In-Reply-To: <20181207102456.1dc67e07@xps13>
Hi Jianxin,
Miquel Raynal <miquel.raynal@bootlin.com> wrote on Fri, 7 Dec 2018
10:24:56 +0100:
> Hi Jianxin,
>
> Looks good to me overall, a few comments inline.
>
> Jianxin Pan <jianxin.pan@amlogic.com> wrote on Sat, 17 Nov 2018
> 00:40:38 +0800:
>
> > From: Liang Yang <liang.yang@amlogic.com>
> >
> > Add initial support for the Amlogic NAND flash controller which found
> > in the Meson-GXBB/GXL/AXG SoCs.
> >
> > Signed-off-by: Liang Yang <liang.yang@amlogic.com>
> > Signed-off-by: Yixun Lan <yixun.lan@amlogic.com>
> > Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
> > ---
> > drivers/mtd/nand/raw/Kconfig | 10 +
> > drivers/mtd/nand/raw/Makefile | 1 +
> > drivers/mtd/nand/raw/meson_nand.c | 1417 +++++++++++++++++++++++++++++++++++++
> > 3 files changed, 1428 insertions(+)
> > create mode 100644 drivers/mtd/nand/raw/meson_nand.c
> >
I forgot to mention, Boris has done more cleanup which breaks your
patches, please have a look at the following commits in the nand/next
branch, they will force you to do some light rework to get the driver
building (especially, you should not export the ->select_chip hook anymore):
7a08dbaedd36 mtd: rawnand: Move ->setup_data_interface() to nand_controller_ops
f2abfeb2078b mtd: rawnand: Move the ->exec_op() method to nand_controller_ops
7d6c37e90cf9 mtd: rawnand: Deprecate the ->select_chip() hook
1770022ffa85 mtd: rawnand: ams-delta: Stop implementing ->select_chip()
653c57c7da08 mtd: rawnand: vf610: Stop implementing ->select_chip()
2ace451cae22 mtd: rawnand: tegra: Stop implementing ->select_chip()
b25251414f6e mtd: rawnand: marvell: Stop implementing ->select_chip()
550b9fc4e3af mtd: rawnand: fsmc: Stop implementing ->select_chip()
02b4a52604a4 mtd: rawnand: Make ->select_chip() optional when ->exec_op() is implemented
ae2294b10b0f mtd: rawnand: Pass the CS line to be selected in struct nand_operation
1d0178593d14 mtd: rawnand: Add nand_[de]select_target() helpers
Thanks,
Miquèl
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v3] ARM: dts: Add support for Liebherr's BK4 device (vf610 based)
From: Lukasz Majewski @ 2018-12-07 9:29 UTC (permalink / raw)
To: Fabio Estevam
Cc: Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Sascha Hauer, linux-kernel, Stefan Agner, Rob Herring,
Sascha Hauer, Fabio Estevam, Shawn Guo,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <CAOMZO5CUfN7uLf7bsw6Xg4+TNrRYodw11Ekg5ypqyXU6q-UFtg@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 1282 bytes --]
Hi Fabio,
> Hi Lukasz,
>
> On Thu, Dec 6, 2018 at 11:08 AM Lukasz Majewski <lukma@denx.de> wrote:
>
> > I will check this latter this week...
>
> Reading the spi dt-binding it states that the spi slave node is
> optional.
>
> If I remove it like this, then the warning is gone:
Unfortunately, the "slave" node is necessary - the "lwn,bk4" compatible
causes the spidev driver to be bound.
Use space applications on this system use it to perform SPI
transmission.
IMHO, removing the node is not a solution - we shall discover why on
current next we do see such errors.
>
> --- a/arch/arm/boot/dts/vf610-bk4.dts
> +++ b/arch/arm/boot/dts/vf610-bk4.dts
> @@ -109,12 +109,6 @@
> bus-num = <3>;
> status = "okay";
> spi-slave;
> -
> - slave@0 {
> - compatible = "lwn,bk4";
> - spi-max-frequency = <30000000>;
> - reg = <0>;
> - };
> };
>
> &edma0 {
>
> Does spi slave still work without it?
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 1/2] arm64: dts: ti: k3-am65-main: Add ECAP PWM node
From: Vignesh R @ 2018-12-07 9:35 UTC (permalink / raw)
To: Tero Kristo, Nishanth Menon
Cc: devicetree, Rob Herring, linux-kernel, linux-arm-kernel,
Vignesh R
In-Reply-To: <20181207093535.5497-1-vigneshr@ti.com>
Add DT entry for ECAP0 PWM node present in main domain
Signed-off-by: Vignesh R <vigneshr@ti.com>
---
arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
index 916434839603..0a0a8fc5df64 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
@@ -129,4 +129,13 @@
clocks = <&k3_clks 113 1>;
power-domains = <&k3_pds 113>;
};
+
+ ecap0: pwm@3100000 {
+ compatible = "ti,am654-ecap", "ti,am3352-ecap";
+ #pwm-cells = <3>;
+ reg = <0x0 0x03100000 0x0 0x60>;
+ power-domains = <&k3_pds 39>;
+ clocks = <&k3_clks 39 0>;
+ clock-names = "fck";
+ };
};
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/2] arm64: dts: ti: k3-am654-base-board: Enable ECAP PWM
From: Vignesh R @ 2018-12-07 9:35 UTC (permalink / raw)
To: Tero Kristo, Nishanth Menon
Cc: devicetree, Rob Herring, linux-kernel, linux-arm-kernel,
Vignesh R
In-Reply-To: <20181207093535.5497-1-vigneshr@ti.com>
Enable ECAP PWM which is used for LCD backlight.
Signed-off-by: Vignesh R <vigneshr@ti.com>
---
arch/arm64/boot/dts/ti/k3-am654-base-board.dts | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
index bd5a0069191d..49ec2c3f5ef1 100644
--- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
@@ -76,6 +76,12 @@
AM65X_IOPAD(0x000c, PIN_INPUT, 0) /* (E21) I2C1_SDA */
>;
};
+
+ ecap0_pins_default: ecap0-pins-default {
+ pinctrl-single,pins = <
+ AM65X_IOPAD(0x0010, PIN_INPUT, 0) /* (D21) ECAP0_IN_APWM_OUT */
+ >;
+ };
};
&wkup_uart0 {
@@ -125,3 +131,8 @@
pinctrl-0 = <&main_i2c2_pins_default>;
clock-frequency = <400000>;
};
+
+&ecap0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ecap0_pins_default>;
+};
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: WIP: UFS on apq8098
From: Marc Gonzalez @ 2018-12-07 9:29 UTC (permalink / raw)
To: Evan Green
Cc: Jeffrey Hugo, MSM, Stephen Boyd, Bjorn Andersson, Andy Gross,
Nicolas Dechesne, Linux ARM
In-Reply-To: <b1349dd8-ef6f-7506-888a-9204870d040f@free.fr>
On 07/12/2018 09:57, Marc Gonzalez wrote:
> On 06/12/2018 17:45, Evan Green wrote:
>
>> I'll throw my random thought into the hopper here. With one particular
>> brand of UFS part on SDM845 we needed to make sure we banged on the
>> ufs_reset pin before the device would re-initialize fully. My hunch
>> says this is not your issue, but it can't hurt to make sure this is
>> happening.
>
> First of all, thanks for chiming in. I feel I'm close to making this work.
>
> My UFSHC DT node defines:
>
> resets = <&gcc GCC_UFS_BCR>;
> reset-names = "rst";
>
> If I'm not mistaken, the uhfhc driver should tickle the reset register?
> Is the ufs_reset pin something different?
In fact, I based my UFS stuff on your UFS stuff.
[PATCH v5 0/5] arm64: dts: qcom: sdm845: Add UFS DT nodes
I read the comments in that series, including the fact that the "resets"
property is ignored by the ufshc driver.
Grepping for ufs_reset downstream, I see:
$ git grep -i ufs_reset vendor
vendor:arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi: pins = "ufs_reset";
vendor:arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi: * UFS_RESET driver strengths are having
vendor:arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi: * HDRV value | UFS_RESET | Typical GPIO
vendor:arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi: * POR value for UFS_RESET HDRV is 3 which means
vendor:arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi: pins = "ufs_reset";
vendor:arch/arm/boot/dts/qcom/msm8998-svr20-pinctrl.dtsi: pins = "ufs_reset";
vendor:arch/arm/boot/dts/qcom/msm8998-svr20-pinctrl.dtsi: * UFS_RESET driver strengths are having
vendor:arch/arm/boot/dts/qcom/msm8998-svr20-pinctrl.dtsi: * HDRV value | UFS_RESET | Typical GPIO
vendor:arch/arm/boot/dts/qcom/msm8998-svr20-pinctrl.dtsi: * POR value for UFS_RESET HDRV is 3 which means
vendor:arch/arm/boot/dts/qcom/msm8998-svr20-pinctrl.dtsi: pins = "ufs_reset";
vendor:drivers/phy/phy-qcom-ufs-qrbtc-v2.c: writel_relaxed(0x15f, qrbtc_phy->u11_regs + U11_UFS_RESET_REG_OFFSET);
vendor:drivers/phy/phy-qcom-ufs-qrbtc-v2.c: writel_relaxed(0x0, qrbtc_phy->u11_regs + U11_UFS_RESET_REG_OFFSET);
vendor:drivers/phy/phy-qcom-ufs-qrbtc-v2.h:#define U11_UFS_RESET_REG_OFFSET PHY_USR(0x4)
vendor:drivers/pinctrl/qcom/pinctrl-msm8998.c:#define UFS_RESET(pg_name, offset) \
vendor:drivers/pinctrl/qcom/pinctrl-msm8998.c: PINCTRL_PIN(153, "UFS_RESET"),
vendor:drivers/pinctrl/qcom/pinctrl-msm8998.c:static const unsigned int ufs_reset_pins[] = { 153 };
vendor:drivers/pinctrl/qcom/pinctrl-msm8998.c: UFS_RESET(ufs_reset, 0x19d000),
Upstream:
$ git grep -i ufs_reset master
master:Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt: ufs_reset
master:Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.txt: ufs_reset
master:drivers/pinctrl/qcom/pinctrl-msm8998.c:#define UFS_RESET(pg_name, offset) \
master:drivers/pinctrl/qcom/pinctrl-msm8998.c: PINCTRL_PIN(153, "UFS_RESET"),
master:drivers/pinctrl/qcom/pinctrl-msm8998.c:static const unsigned int ufs_reset_pins[] = { 153 };
master:drivers/pinctrl/qcom/pinctrl-msm8998.c: UFS_RESET(ufs_reset, 0x19d000),
master:drivers/pinctrl/qcom/pinctrl-qcs404.c:#define UFS_RESET(pg_name, offset) \
master:drivers/pinctrl/qcom/pinctrl-sdm845.c:#define UFS_RESET(pg_name, offset) \
master:drivers/pinctrl/qcom/pinctrl-sdm845.c: PINCTRL_PIN(153, "UFS_RESET"),
master:drivers/pinctrl/qcom/pinctrl-sdm845.c:static const unsigned int ufs_reset_pins[] = { 153 };
master:drivers/pinctrl/qcom/pinctrl-sdm845.c: UFS_RESET(ufs_reset, 0x99f000),
I need to find the way to make Linux tickle/toggle the ufs_reset pin.
Regards.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] dt-bindings: rtc: sun6i-rtc: Fix register range in example
From: Alexandre Belloni @ 2018-12-07 9:28 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Mark Rutland, Alessandro Zummo, devicetree, Maxime Ripard,
linux-kernel, Rob Herring, linux-arm-kernel, linux-rtc
In-Reply-To: <20181207084719.2009-1-wens@csie.org>
On 07/12/2018 16:47:19+0800, Chen-Yu Tsai wrote:
> The register range for the RTC extends beyond 0x54.
> Use the size from the user manual's memory map instead.
>
> Fixes: 9765d2d94309 ("rtc: sun6i: Add sun6i RTC driver")
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> Documentation/devicetree/bindings/rtc/sun6i-rtc.txt | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Applied, thanks.
--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v7 2/2] mtd: rawnand: meson: add support for Amlogic NAND flash controller
From: Miquel Raynal @ 2018-12-07 9:24 UTC (permalink / raw)
To: Jianxin Pan
Cc: Rob Herring, Hanjie Lin, Victor Wan, Marek Vasut,
Martin Blumenstingl, Richard Weinberger, Neil Armstrong,
Yixun Lan, linux-kernel, Boris Brezillon, Jian Hu, Liang Yang,
linux-mtd, Kevin Hilman, Carlo Caione, linux-amlogic,
Brian Norris, David Woodhouse, linux-arm-kernel, Jerome Brunet
In-Reply-To: <1542386439-30166-3-git-send-email-jianxin.pan@amlogic.com>
Hi Jianxin,
Looks good to me overall, a few comments inline.
Jianxin Pan <jianxin.pan@amlogic.com> wrote on Sat, 17 Nov 2018
00:40:38 +0800:
> From: Liang Yang <liang.yang@amlogic.com>
>
> Add initial support for the Amlogic NAND flash controller which found
> in the Meson-GXBB/GXL/AXG SoCs.
>
> Signed-off-by: Liang Yang <liang.yang@amlogic.com>
> Signed-off-by: Yixun Lan <yixun.lan@amlogic.com>
> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
> ---
> drivers/mtd/nand/raw/Kconfig | 10 +
> drivers/mtd/nand/raw/Makefile | 1 +
> drivers/mtd/nand/raw/meson_nand.c | 1417 +++++++++++++++++++++++++++++++++++++
> 3 files changed, 1428 insertions(+)
> create mode 100644 drivers/mtd/nand/raw/meson_nand.c
>
> diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
> index c7efc31..223b041 100644
> --- a/drivers/mtd/nand/raw/Kconfig
> +++ b/drivers/mtd/nand/raw/Kconfig
> @@ -541,4 +541,14 @@ config MTD_NAND_TEGRA
> is supported. Extra OOB bytes when using HW ECC are currently
> not supported.
>
> +config MTD_NAND_MESON
> + tristate "Support for NAND controller on Amlogic's Meson SoCs"
> + depends on ARCH_MESON || COMPILE_TEST
> + depends on COMMON_CLK_AMLOGIC
> + select COMMON_CLK_REGMAP_MESON
> + select MFD_SYSCON
> + help
> + Enables support for NAND controller on Amlogic's Meson SoCs.
> + This controller is found on Meson GXBB, GXL, AXG SoCs.
> +
> endif # MTD_NAND
> diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
> index 57159b3..a2cc2fe 100644
> --- a/drivers/mtd/nand/raw/Makefile
> +++ b/drivers/mtd/nand/raw/Makefile
> @@ -56,6 +56,7 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
> obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
> obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
> obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
> +obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
>
> nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
> nand-objs += nand_onfi.o
> diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c
> new file mode 100644
> index 0000000..c566636
> --- /dev/null
> +++ b/drivers/mtd/nand/raw/meson_nand.c
> @@ -0,0 +1,1417 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Amlogic Meson Nand Flash Controller Driver
> + *
> + * Copyright (c) 2018 Amlogic, inc.
> + * Author: Liang Yang <liang.yang@amlogic.com>
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/interrupt.h>
> +#include <linux/clk.h>
> +#include <linux/mtd/rawnand.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/iopoll.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +
> +#define NFC_REG_CMD 0x00
> +#define NFC_CMD_DRD (0x8 << 14)
> +#define NFC_CMD_IDLE (0xc << 14)
> +#define NFC_CMD_DWR (0x4 << 14)
> +#define NFC_CMD_CLE (0x5 << 14)
> +#define NFC_CMD_ALE (0x6 << 14)
> +#define NFC_CMD_ADL ((0 << 16) | (3 << 20))
> +#define NFC_CMD_ADH ((1 << 16) | (3 << 20))
> +#define NFC_CMD_AIL ((2 << 16) | (3 << 20))
> +#define NFC_CMD_AIH ((3 << 16) | (3 << 20))
> +#define NFC_CMD_SEED ((8 << 16) | (3 << 20))
> +#define NFC_CMD_M2N ((0 << 17) | (2 << 20))
> +#define NFC_CMD_N2M ((1 << 17) | (2 << 20))
> +#define NFC_CMD_RB BIT(20)
> +#define NFC_CMD_IO6 ((0xb << 10) | (1 << 18))
> +#define NFC_CMD_SCRAMBLER_ENABLE BIT(19)
> +#define NFC_CMD_RB_INT BIT(14)
> +
> +#define NFC_CMD_GET_SIZE(x) (((x) >> 22) & GENMASK(4, 0))
> +
> +#define NFC_REG_CFG 0x04
> +#define NFC_REG_DADR 0x08
> +#define NFC_REG_IADR 0x0c
> +#define NFC_REG_BUF 0x10
> +#define NFC_REG_INFO 0x14
> +#define NFC_REG_DC 0x18
> +#define NFC_REG_ADR 0x1c
> +#define NFC_REG_DL 0x20
> +#define NFC_REG_DH 0x24
> +#define NFC_REG_CADR 0x28
> +#define NFC_REG_SADR 0x2c
> +#define NFC_REG_PINS 0x30
> +#define NFC_REG_VER 0x38
> +
> +#define NFC_RB_IRQ_EN BIT(21)
> +#define NFC_INT_MASK (3 << 20)
> +
> +#define CMDRWGEN(cmd_dir, ran, bch, short_mode, page_size, pages) \
> + ( \
> + (cmd_dir) | \
> + ((ran) << 19) | \
> + ((bch) << 14) | \
> + ((short_mode) << 13) | \
> + (((page_size) & 0x7f) << 6) | \
> + ((pages) & 0x3f) \
> + )
> +
> +#define GENCMDDADDRL(adl, addr) ((adl) | ((addr) & 0xffff))
> +#define GENCMDDADDRH(adh, addr) ((adh) | (((addr) >> 16) & 0xffff))
> +#define GENCMDIADDRL(ail, addr) ((ail) | ((addr) & 0xffff))
> +#define GENCMDIADDRH(aih, addr) ((aih) | (((addr) >> 16) & 0xffff))
> +
> +#define RB_STA(x) (1 << (26 + (x)))
> +#define DMA_DIR(dir) ((dir) ? NFC_CMD_N2M : NFC_CMD_M2N)
> +
> +#define ECC_CHECK_RETURN_FF (-1)
> +
> +#define NAND_CE0 (0xe << 10)
> +#define NAND_CE1 (0xd << 10)
> +
> +#define DMA_BUSY_TIMEOUT 0x100000
> +#define CMD_FIFO_EMPTY_TIMEOUT 1000
> +
> +#define MAX_CE_NUM 2
> +
> +/* eMMC clock register, misc control */
> +#define SD_EMMC_CLOCK 0x00
> +#define CLK_ALWAYS_ON BIT(28)
> +#define CLK_SELECT_NAND BIT(31)
> +#define CLK_DIV_MASK GENMASK(5, 0)
> +
> +#define NFC_CLK_CYCLE 6
> +
> +/* nand flash controller delay 3 ns */
> +#define NFC_DEFAULT_DELAY 3000
> +
> +#define MAX_ECC_INDEX 10
> +
> +#define MUX_CLK_NUM_PARENTS 2
> +
> +#define ROW_ADDER(page, index) (((page) >> (8 * (index))) & 0xff)
> +#define MAX_CYCLE_ADDRS 5
> +#define DIRREAD 1
> +#define DIRWRITE 0
> +
> +#define ECC_PARITY_BCH8_512B 14
> +
> +#define PER_INFO_BYTE 8
> +
> +#define ECC_COMPLETE BIT(31)
> +#define ECC_ERR_CNT(x) (((x) >> 24) & GENMASK(5, 0))
> +#define ECC_ZERO_CNT(x) (((x) >> 16) & GENMASK(5, 0))
> +
> +struct meson_nfc_nand_chip {
> + struct list_head node;
> + struct nand_chip nand;
> + unsigned long clk_rate;
> + unsigned long level1_divider;
> + u32 bus_timing;
> + u32 twb;
> + u32 tadl;
> + u32 tbers_max;
> +
> + u32 bch_mode;
> + u8 *data_buf;
> + __le64 *info_buf;
> + u32 nsels;
> + u8 sels[0];
> +};
> +
> +struct meson_nand_ecc {
> + u32 bch;
> + u32 strength;
> +};
> +
> +struct meson_nfc_data {
> + const struct nand_ecc_caps *ecc_caps;
> +};
> +
> +struct meson_nfc_param {
> + u32 chip_select;
> + u32 rb_select;
> +};
> +
> +struct nand_rw_cmd {
> + u32 cmd0;
> + u32 addrs[MAX_CYCLE_ADDRS];
> + u32 cmd1;
> +};
> +
> +struct nand_timing {
> + u32 twb;
> + u32 tadl;
> + u32 tbers_max;
> +};
> +
> +struct meson_nfc {
> + struct nand_controller controller;
> + struct clk *core_clk;
> + struct clk *device_clk;
> + struct clk *phase_tx;
> + struct clk *phase_rx;
> +
> + unsigned long clk_rate;
> + u32 bus_timing;
> +
> + struct device *dev;
> + void __iomem *reg_base;
> + struct regmap *reg_clk;
> + struct completion completion;
> + struct list_head chips;
> + const struct meson_nfc_data *data;
> + struct meson_nfc_param param;
> + struct nand_timing timing;
> + union {
> + int cmd[32];
> + struct nand_rw_cmd rw;
> + } cmdfifo;
> +
> + dma_addr_t daddr;
> + dma_addr_t iaddr;
> +
> + unsigned long assigned_cs;
> +};
> +
> +enum {
> + NFC_ECC_BCH8_1K = 2,
> + NFC_ECC_BCH24_1K,
> + NFC_ECC_BCH30_1K,
> + NFC_ECC_BCH40_1K,
> + NFC_ECC_BCH50_1K,
> + NFC_ECC_BCH60_1K,
> +};
> +
> +#define MESON_ECC_DATA(b, s) { .bch = (b), .strength = (s)}
> +
> +static int meson_nand_calc_ecc_bytes(int step_size, int strength)
> +{
> + int ecc_bytes;
> +
> + if (step_size == 512 && strength == 8)
> + return ECC_PARITY_BCH8_512B;
> +
> + ecc_bytes = DIV_ROUND_UP(strength * fls(step_size * 8), 8);
> + ecc_bytes = ALIGN(ecc_bytes, 2);
> +
> + return ecc_bytes;
> +}
> +
> +NAND_ECC_CAPS_SINGLE(meson_gxl_ecc_caps,
> + meson_nand_calc_ecc_bytes, 1024, 8, 24, 30, 40, 50, 60);
> +NAND_ECC_CAPS_SINGLE(meson_axg_ecc_caps,
> + meson_nand_calc_ecc_bytes, 1024, 8);
> +
> +static struct meson_nfc_nand_chip *to_meson_nand(struct nand_chip *nand)
> +{
> + return container_of(nand, struct meson_nfc_nand_chip, nand);
> +}
> +
> +static void meson_nfc_select_chip(struct nand_chip *nand, int chip)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + int ret, value;
> +
> + if (chip < 0 || WARN_ON_ONCE(chip > MAX_CE_NUM))
> + return;
> +
> + nfc->param.chip_select = meson_chip->sels[chip] ? NAND_CE1 : NAND_CE0;
> + nfc->param.rb_select = nfc->param.chip_select;
> + nfc->timing.twb = meson_chip->twb;
> + nfc->timing.tadl = meson_chip->tadl;
> + nfc->timing.tbers_max = meson_chip->tbers_max;
> +
> + if (chip >= 0) {
> + if (nfc->clk_rate != meson_chip->clk_rate) {
> + ret = clk_set_rate(nfc->device_clk,
> + meson_chip->clk_rate);
> + if (ret) {
> + dev_err(nfc->dev, "failed to set clock rate\n");
> + return;
> + }
> + nfc->clk_rate = meson_chip->clk_rate;
> + }
> + if (nfc->bus_timing != meson_chip->bus_timing) {
> + value = (NFC_CLK_CYCLE - 1)
> + | (meson_chip->bus_timing << 5);
> + writel(value, nfc->reg_base + NFC_REG_CFG);
> + writel((1 << 31), nfc->reg_base + NFC_REG_CMD);
> + nfc->bus_timing = meson_chip->bus_timing;
> + }
> + }
Don't you have timing registers to set?
> +}
> +
> +static void meson_nfc_cmd_idle(struct meson_nfc *nfc, u32 time)
> +{
> + writel(nfc->param.chip_select | NFC_CMD_IDLE | (time & 0x3ff),
> + nfc->reg_base + NFC_REG_CMD);
> +}
> +
> +static void meson_nfc_cmd_seed(struct meson_nfc *nfc, u32 seed)
> +{
> + writel(NFC_CMD_SEED | (0xc2 + (seed & 0x7fff)),
> + nfc->reg_base + NFC_REG_CMD);
> +}
> +
> +static void meson_nfc_cmd_access(struct nand_chip *nand, int raw, bool dir)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct meson_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + u32 bch = meson_chip->bch_mode, cmd;
> + int len = mtd->writesize, pagesize, pages;
> + int scramble = (nand->options & NAND_NEED_SCRAMBLING) ? 1 : 0;
There are quite a few places where you use hardcoded values, I would
have preferred preprocessor defines for that. In this case, something
link:
// naming is just as a reference, use whatever you want
+#define CMD_SCRAMBLE BIT(19)
[...]
+int scramble = nand->options & NAND_NEED_SCRAMBLING) ? CMD_SCRAMBLE : 0;
would be better (you can extend to other places as well).
> +
> + pagesize = nand->ecc.size;
> +
> + if (raw) {
> + len = mtd->writesize + mtd->oobsize;
> + cmd = (len & 0x3fff) | (scramble << 19) | DMA_DIR(dir);
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> + return;
> + }
> +
> + pages = len / nand->ecc.size;
> +
> + cmd = CMDRWGEN(DMA_DIR(dir), scramble, bch, 0, pagesize, pages);
> +
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> +}
> +
> +static void meson_nfc_drain_cmd(struct meson_nfc *nfc)
> +{
> + /*
> + * Insert two commands to make sure all valid commands are finished.
> + *
> + * The Nand flash controller is designed as two stages pipleline -
> + * a) fetch and b) excute.
> + * There might be cases when the driver see command queue is empty,
> + * but the Nand flash controller still has two commands buffered,
> + * one is fetched into NFC request queue (ready to run), and another
> + * is actively executing. So pushing 2 "IDLE" commands guarantees that
> + * the pipeline is emptied.
> + */
> + meson_nfc_cmd_idle(nfc, 0);
> + meson_nfc_cmd_idle(nfc, 0);
> +}
> +
> +static int meson_nfc_wait_cmd_finish(struct meson_nfc *nfc,
> + unsigned int timeout_ms)
> +{
> + u32 cmd_size = 0;
> + int ret;
> +
> + /* wait cmd fifo is empty */
> + ret = readl_relaxed_poll_timeout(nfc->reg_base + NFC_REG_CMD, cmd_size,
> + !NFC_CMD_GET_SIZE(cmd_size),
> + 10, timeout_ms * 1000);
> + if (ret)
> + dev_err(nfc->dev, "wait for empty cmd FIFO time out\n");
> +
> + return ret;
> +}
> +
> +static int meson_nfc_wait_dma_finish(struct meson_nfc *nfc)
> +{
> + meson_nfc_drain_cmd(nfc);
> +
> + return meson_nfc_wait_cmd_finish(nfc, DMA_BUSY_TIMEOUT);
> +}
> +
> +static u8 *meson_nfc_oob_ptr(struct nand_chip *nand, int i)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + int len;
> +
> + len = nand->ecc.size * (i + 1) + (nand->ecc.bytes + 2) * i;
> +
> + return meson_chip->data_buf + len;
> +}
> +
> +static u8 *meson_nfc_data_ptr(struct nand_chip *nand, int i)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + int len, temp;
> +
> + temp = nand->ecc.size + nand->ecc.bytes;
> + len = (temp + 2) * i;
> +
> + return meson_chip->data_buf + len;
> +}
> +
> +static void meson_nfc_get_data_oob(struct nand_chip *nand,
> + u8 *buf, u8 *oobbuf)
> +{
> + int i, oob_len = 0;
> + u8 *dsrc, *osrc;
> +
> + oob_len = nand->ecc.bytes + 2;
> + for (i = 0; i < nand->ecc.steps; i++) {
> + if (buf) {
> + dsrc = meson_nfc_data_ptr(nand, i);
> + memcpy(buf, dsrc, nand->ecc.size);
> + buf += nand->ecc.size;
> + }
> + osrc = meson_nfc_oob_ptr(nand, i);
> + memcpy(oobbuf, osrc, oob_len);
> + oobbuf += oob_len;
> + }
> +}
> +
> +static void meson_nfc_set_data_oob(struct nand_chip *nand,
> + const u8 *buf, u8 *oobbuf)
> +{
> + int i, oob_len = 0;
> + u8 *dsrc, *osrc;
> +
> + oob_len = nand->ecc.bytes + 2;
> + for (i = 0; i < nand->ecc.steps; i++) {
> + if (buf) {
> + dsrc = meson_nfc_data_ptr(nand, i);
> + memcpy(dsrc, buf, nand->ecc.size);
> + buf += nand->ecc.size;
> + }
> + osrc = meson_nfc_oob_ptr(nand, i);
> + memcpy(osrc, oobbuf, oob_len);
> + oobbuf += oob_len;
> + }
> +}
> +
> +static int meson_nfc_queue_rb(struct meson_nfc *nfc, int timeout_ms)
> +{
> + u32 cmd, cfg;
> + int ret = 0;
> +
> + meson_nfc_cmd_idle(nfc, nfc->timing.twb);
> + meson_nfc_drain_cmd(nfc);
> + meson_nfc_wait_cmd_finish(nfc, CMD_FIFO_EMPTY_TIMEOUT);
> +
> + cfg = readl(nfc->reg_base + NFC_REG_CFG);
> + cfg |= (1 << 21);
> + writel(cfg, nfc->reg_base + NFC_REG_CFG);
> +
> + init_completion(&nfc->completion);
> +
> + /* use the max erase time as the maximum clock for waiting R/B */
> + cmd = NFC_CMD_RB | NFC_CMD_RB_INT
> + | nfc->param.chip_select | nfc->timing.tbers_max;
Nit: I think the '|' should be on the previous line.
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> +
> + ret = wait_for_completion_timeout(&nfc->completion,
> + msecs_to_jiffies(timeout_ms));
> + if (ret == 0)
> + ret = -1;
> +
> + return ret;
> +}
> +
> +static void meson_nfc_set_user_byte(struct nand_chip *nand, u8 *oob_buf)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + __le64 *info;
> + int i, count;
> +
> + for (i = 0, count = 0; i < nand->ecc.steps; i++, count += 2) {
> + info = &meson_chip->info_buf[i];
> + *info |= oob_buf[count];
> + *info |= oob_buf[count + 1] << 8;
> + }
> +}
> +
> +static void meson_nfc_get_user_byte(struct nand_chip *nand, u8 *oob_buf)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + __le64 *info;
> + int i, count;
> +
> + for (i = 0, count = 0; i < nand->ecc.steps; i++, count += 2) {
> + info = &meson_chip->info_buf[i];
> + oob_buf[count] = *info;
> + oob_buf[count + 1] = *info >> 8;
> + }
> +}
> +
> +static int meson_nfc_ecc_correct(struct nand_chip *nand)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + __le64 *info;
> + u32 bitflips = 0, i;
> + int scramble;
> + u8 zero_cnt;
> +
> + scramble = (nand->options & NAND_NEED_SCRAMBLING) ? 1 : 0;
> +
> + for (i = 0; i < nand->ecc.steps; i++) {
> + info = &meson_chip->info_buf[i];
> + if (ECC_ERR_CNT(*info) == 0x3f) {
> + zero_cnt = ECC_ZERO_CNT(*info);
> + if (scramble && zero_cnt < nand->ecc.strength)
> + return ECC_CHECK_RETURN_FF;
This and what you do later with ECC_CHECK_RETURN_FF is pretty unclear
to me.
> + mtd->ecc_stats.failed++;
> + continue;
> + }
> + mtd->ecc_stats.corrected += ECC_ERR_CNT(*info);
> + bitflips = max_t(u32, bitflips, ECC_ERR_CNT(*info));
> + }
Are you sure you handle correctly empty pages with bf?
> +
> + return bitflips;
> +}
> +
> +static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, u8 *databuf,
> + int datalen, u8 *infobuf, int infolen,
> + enum dma_data_direction dir)
> +{
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + u32 cmd;
> + int ret = 0;
> +
> + nfc->daddr = dma_map_single(nfc->dev, (void *)databuf, datalen, dir);
> + ret = dma_mapping_error(nfc->dev, nfc->daddr);
> + if (ret) {
> + dev_err(nfc->dev, "dma mapping error\n");
> + return ret;
> + }
> + cmd = GENCMDDADDRL(NFC_CMD_ADL, nfc->daddr);
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> +
> + cmd = GENCMDDADDRH(NFC_CMD_ADH, nfc->daddr);
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> +
> + if (infobuf) {
> + nfc->iaddr = dma_map_single(nfc->dev, infobuf, infolen, dir);
> + ret = dma_mapping_error(nfc->dev, nfc->iaddr);
> + if (ret) {
> + dev_err(nfc->dev, "dma mapping error\n");
> + dma_unmap_single(nfc->dev,
> + nfc->daddr, datalen, dir);
> + return ret;
> + }
> + cmd = GENCMDIADDRL(NFC_CMD_AIL, nfc->iaddr);
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> +
> + cmd = GENCMDIADDRH(NFC_CMD_AIH, nfc->iaddr);
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> + }
> +
> + return ret;
> +}
> +
> +static void meson_nfc_dma_buffer_release(struct nand_chip *nand,
> + int infolen, int datalen,
> + enum dma_data_direction dir)
> +{
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> +
> + dma_unmap_single(nfc->dev, nfc->daddr, datalen, dir);
> + if (infolen)
> + dma_unmap_single(nfc->dev, nfc->iaddr, infolen, dir);
> +}
> +
> +static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len)
> +{
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + int ret = 0;
> + u32 cmd;
> + u8 *info;
> +
> + info = kzalloc(PER_INFO_BYTE, GFP_KERNEL);
> + ret = meson_nfc_dma_buffer_setup(nand, buf, len, info,
> + PER_INFO_BYTE, DMA_FROM_DEVICE);
> + if (ret)
> + return ret;
> +
> + cmd = NFC_CMD_N2M | (len & 0x3fff);
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> +
> + meson_nfc_drain_cmd(nfc);
> + meson_nfc_wait_cmd_finish(nfc, 1000);
> + meson_nfc_dma_buffer_release(nand, len, PER_INFO_BYTE, DMA_FROM_DEVICE);
> + kfree(info);
> +
> + return ret;
> +}
> +
> +static int meson_nfc_write_buf(struct nand_chip *nand, u8 *buf, int len)
> +{
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + int ret = 0;
> + u32 cmd;
> +
> + ret = meson_nfc_dma_buffer_setup(nand, buf, len, NULL,
> + 0, DMA_TO_DEVICE);
> + if (ret)
> + return ret;
> +
> + cmd = NFC_CMD_M2N | (len & 0x3fff);
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> +
> + meson_nfc_drain_cmd(nfc);
> + meson_nfc_wait_cmd_finish(nfc, 1000);
> + meson_nfc_dma_buffer_release(nand, len, 0, DMA_TO_DEVICE);
> +
> + return ret;
> +}
> +
> +static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
> + int page, bool in)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + const struct nand_sdr_timings *sdr =
> + nand_get_sdr_timings(&nand->data_interface);
> + u32 *addrs = nfc->cmdfifo.rw.addrs;
> + u32 cs = nfc->param.chip_select;
> + u32 cmd0, cmd_num, row_start;
> + int ret = 0, i;
> +
> + cmd_num = sizeof(struct nand_rw_cmd) / sizeof(int);
> +
> + cmd0 = in ? NAND_CMD_READ0 : NAND_CMD_SEQIN;
> + nfc->cmdfifo.rw.cmd0 = cs | NFC_CMD_CLE | cmd0;
> +
> + addrs[0] = cs | NFC_CMD_ALE | 0;
> + if (mtd->writesize <= 512) {
> + cmd_num--;
> + row_start = 1;
> + } else {
> + addrs[1] = cs | NFC_CMD_ALE | 0;
> + row_start = 2;
> + }
> +
> + addrs[row_start] = cs | NFC_CMD_ALE | ROW_ADDER(page, 0);
> + addrs[row_start + 1] = cs | NFC_CMD_ALE | ROW_ADDER(page, 1);
> +
> + if (nand->options & NAND_ROW_ADDR_3)
> + addrs[row_start + 2] =
> + cs | NFC_CMD_ALE | ROW_ADDER(page, 2);
> + else
> + cmd_num--;
> +
> + /* subtract cmd1 */
> + cmd_num--;
> +
> + for (i = 0; i < cmd_num; i++)
> + writel_relaxed(nfc->cmdfifo.cmd[i],
> + nfc->reg_base + NFC_REG_CMD);
> +
> + if (in) {
> + nfc->cmdfifo.rw.cmd1 = cs | NFC_CMD_CLE | NAND_CMD_READSTART;
> + writel(nfc->cmdfifo.rw.cmd1, nfc->reg_base + NFC_REG_CMD);
> + meson_nfc_queue_rb(nfc, PSEC_TO_MSEC(sdr->tR_max));
> + } else {
> + meson_nfc_cmd_idle(nfc, nfc->timing.tadl);
> + }
> +
> + return ret;
> +}
> +
> +static int meson_nfc_write_page_sub(struct nand_chip *nand,
> + int page, int raw)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + const struct nand_sdr_timings *sdr =
> + nand_get_sdr_timings(&nand->data_interface);
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + int data_len, info_len;
> + u32 cmd;
> + int ret;
> +
> + data_len = mtd->writesize + mtd->oobsize;
> + info_len = nand->ecc.steps * PER_INFO_BYTE;
> +
> + ret = meson_nfc_rw_cmd_prepare_and_execute(nand, page, DIRWRITE);
> + if (ret)
> + return ret;
> +
> + ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf,
> + data_len, (u8 *)meson_chip->info_buf,
> + info_len, DMA_TO_DEVICE);
> + if (ret)
> + return ret;
> +
> + meson_nfc_cmd_seed(nfc, page);
> + meson_nfc_cmd_access(nand, raw, DIRWRITE);
> + cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_PAGEPROG;
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> + meson_nfc_queue_rb(nfc, PSEC_TO_MSEC(sdr->tPROG_max));
> +
> + meson_nfc_dma_buffer_release(nand, data_len, info_len, DMA_TO_DEVICE);
> +
> + return ret;
> +}
> +
> +static int meson_nfc_write_page_raw(struct nand_chip *nand, const u8 *buf,
> + int oob_required, int page)
> +{
> + u8 *oob_buf = nand->oob_poi;
> +
> + meson_nfc_set_data_oob(nand, buf, oob_buf);
> +
> + return meson_nfc_write_page_sub(nand, page, 1);
> +}
> +
> +static int meson_nfc_write_page_hwecc(struct nand_chip *nand,
> + const u8 *buf, int oob_required, int page)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + u8 *oob_buf = nand->oob_poi;
> +
> + memcpy(meson_chip->data_buf, buf, mtd->writesize);
> + memset(meson_chip->info_buf, 0, nand->ecc.steps * PER_INFO_BYTE);
> + meson_nfc_set_user_byte(nand, oob_buf);
> +
> + return meson_nfc_write_page_sub(nand, page, 0);
> +}
> +
> +static void meson_nfc_check_ecc_pages_valid(struct meson_nfc *nfc,
> + struct nand_chip *nand, int raw)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + __le64 *info;
> + u32 neccpages;
> + int ret;
> +
> + neccpages = raw ? 1 : nand->ecc.steps;
> + info = &meson_chip->info_buf[neccpages - 1];
> + do {
> + usleep_range(10, 15);
> + /* info is updated by nfc dma engine*/
> + smp_rmb();
> + ret = *info & ECC_COMPLETE;
> + } while (!ret);
> +}
> +
> +static int meson_nfc_read_page_sub(struct nand_chip *nand,
> + int page, int raw)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + int data_len, info_len;
> + int ret;
> +
> + data_len = mtd->writesize + mtd->oobsize;
> + info_len = nand->ecc.steps * PER_INFO_BYTE;
> +
> + ret = meson_nfc_rw_cmd_prepare_and_execute(nand, page, DIRREAD);
> + if (ret)
> + return ret;
> +
> + ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf,
> + data_len, (u8 *)meson_chip->info_buf,
> + info_len, DMA_FROM_DEVICE);
> + if (ret)
> + return ret;
> +
> + meson_nfc_cmd_seed(nfc, page);
> + meson_nfc_cmd_access(nand, raw, DIRREAD);
> + ret = meson_nfc_wait_dma_finish(nfc);
> + meson_nfc_check_ecc_pages_valid(nfc, nand, raw);
> +
> + meson_nfc_dma_buffer_release(nand, data_len, info_len, DMA_FROM_DEVICE);
> +
> + return ret;
> +}
> +
> +static int meson_nfc_read_page_raw(struct nand_chip *nand, u8 *buf,
> + int oob_required, int page)
> +{
> + u8 *oob_buf = nand->oob_poi;
> + int ret;
> +
> + ret = meson_nfc_read_page_sub(nand, page, 1);
> + if (ret)
> + return ret;
> +
> + meson_nfc_get_data_oob(nand, buf, oob_buf);
> +
> + return 0;
> +}
> +
> +static int meson_nfc_read_page_hwecc(struct nand_chip *nand, u8 *buf,
> + int oob_required, int page)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + u8 *oob_buf = nand->oob_poi;
> + int ret;
> +
> + ret = meson_nfc_read_page_sub(nand, page, 0);
> + if (ret)
> + return ret;
> +
> + meson_nfc_get_user_byte(nand, oob_buf);
> +
> + ret = meson_nfc_ecc_correct(nand);
> + if (ret == ECC_CHECK_RETURN_FF) {
> + if (buf)
> + memset(buf, 0xff, mtd->writesize);
> +
> + memset(oob_buf, 0xff, mtd->oobsize);
> + return 0;
> + }
> +
> + if (buf && buf != meson_chip->data_buf)
> + memcpy(buf, meson_chip->data_buf, mtd->writesize);
> +
> + return ret;
> +}
> +
> +static int meson_nfc_read_oob_raw(struct nand_chip *nand, int page)
> +{
> + return meson_nfc_read_page_raw(nand, NULL, 1, page);
> +}
> +
> +static int meson_nfc_read_oob(struct nand_chip *nand, int page)
> +{
> + return meson_nfc_read_page_hwecc(nand, NULL, 1, page);
> +}
> +
> +void *
> +meson_nand_op_get_dma_safe_input_buf(const struct nand_op_instr *instr)
> +{
> + if (WARN_ON(instr->type != NAND_OP_DATA_IN_INSTR))
> + return NULL;
> + if (virt_addr_valid(instr->ctx.data.buf.in) &&
> + !object_is_on_stack(instr->ctx.data.buf.in))
> + return instr->ctx.data.buf.in;
> +
> + return kzalloc(instr->ctx.data.len, GFP_KERNEL);
I think allocating memory and using it without ever testing the
allocation succeeded is wrong. You do that in many places. I would like
to see allocations properly handled.
> +}
> +
> +void
> +meson_nand_op_put_dma_safe_input_buf(const struct nand_op_instr *instr,
> + void *buf)
> +{
> + if (WARN_ON(instr->type != NAND_OP_DATA_IN_INSTR) ||
> + WARN_ON(!buf))
> + return;
> + if (buf == instr->ctx.data.buf.in)
> + return;
> +
> + memcpy(instr->ctx.data.buf.in, buf, instr->ctx.data.len);
> + kfree(buf);
> +}
> +
> +const void *
> +meson_nand_op_get_dma_safe_output_buf(const struct nand_op_instr *instr)
> +{
> + if (WARN_ON(instr->type != NAND_OP_DATA_OUT_INSTR))
> + return NULL;
> +
> + if (virt_addr_valid(instr->ctx.data.buf.out) &&
> + !object_is_on_stack(instr->ctx.data.buf.out))
Can you please create helpers for that? I guess it will help removing
these checks once the core will have a DMA-safe approach.
> + return instr->ctx.data.buf.out;
> +
> + return kmemdup(instr->ctx.data.buf.out,
> + instr->ctx.data.len, GFP_KERNEL);
> +}
> +
> +void
> +meson_nand_op_put_dma_safe_output_buf(const struct nand_op_instr *instr,
> + const void *buf)
> +{
> + if (WARN_ON(instr->type != NAND_OP_DATA_OUT_INSTR) ||
> + WARN_ON(!buf))
> + return;
> +
> + if (buf != instr->ctx.data.buf.out)
> + kfree(buf);
> +}
> +
> +static int meson_nfc_exec_op(struct nand_chip *nand,
> + const struct nand_operation *op, bool check_only)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + const struct nand_op_instr *instr = NULL;
> + void *buf;
> + u32 op_id, delay_idle, cmd;
> + int i;
> +
> + for (op_id = 0; op_id < op->ninstrs; op_id++) {
> + instr = &op->instrs[op_id];
> + delay_idle = DIV_ROUND_UP(PSEC_TO_NSEC(instr->delay_ns),
> + meson_chip->level1_divider *
> + NFC_CLK_CYCLE);
> + switch (instr->type) {
> + case NAND_OP_CMD_INSTR:
> + cmd = nfc->param.chip_select | NFC_CMD_CLE;
> + cmd |= instr->ctx.cmd.opcode & 0xff;
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> + meson_nfc_cmd_idle(nfc, delay_idle);
> + break;
> +
> + case NAND_OP_ADDR_INSTR:
> + for (i = 0; i < instr->ctx.addr.naddrs; i++) {
> + cmd = nfc->param.chip_select | NFC_CMD_ALE;
> + cmd |= instr->ctx.addr.addrs[i] & 0xff;
> + writel(cmd, nfc->reg_base + NFC_REG_CMD);
> + }
> + meson_nfc_cmd_idle(nfc, delay_idle);
> + break;
> +
> + case NAND_OP_DATA_IN_INSTR:
> + buf = meson_nand_op_get_dma_safe_input_buf(instr);
> + meson_nfc_read_buf(nand, buf,
> + instr->ctx.data.len);
> + meson_nand_op_put_dma_safe_input_buf(instr, buf);
> + break;
> +
> + case NAND_OP_DATA_OUT_INSTR:
> + buf =
> + (void *)meson_nand_op_get_dma_safe_output_buf(instr);
> + meson_nfc_write_buf(nand, buf,
> + instr->ctx.data.len);
> + meson_nand_op_put_dma_safe_output_buf(instr, buf);
> + break;
> +
> + case NAND_OP_WAITRDY_INSTR:
> + meson_nfc_queue_rb(nfc, instr->ctx.waitrdy.timeout_ms);
> + if (instr->delay_ns)
> + meson_nfc_cmd_idle(nfc, delay_idle);
> + break;
> + }
> + }
> + meson_nfc_wait_cmd_finish(nfc, 1000);
> + return 0;
> +}
> +
> +static int meson_ooblayout_ecc(struct mtd_info *mtd, int section,
> + struct mtd_oob_region *oobregion)
> +{
> + struct nand_chip *nand = mtd_to_nand(mtd);
> +
> + if (section >= nand->ecc.steps)
> + return -ERANGE;
> +
> + oobregion->offset = 2 + (section * (2 + nand->ecc.bytes));
> + oobregion->length = nand->ecc.bytes;
> +
> + return 0;
> +}
> +
> +static int meson_ooblayout_free(struct mtd_info *mtd, int section,
> + struct mtd_oob_region *oobregion)
> +{
> + struct nand_chip *nand = mtd_to_nand(mtd);
> +
> + if (section >= nand->ecc.steps)
> + return -ERANGE;
> +
> + oobregion->offset = section * (2 + nand->ecc.bytes);
> + oobregion->length = 2;
> +
> + return 0;
> +}
> +
> +static const struct mtd_ooblayout_ops meson_ooblayout_ops = {
> + .ecc = meson_ooblayout_ecc,
> + .free = meson_ooblayout_free,
> +};
> +
> +static int meson_nfc_clk_init(struct meson_nfc *nfc)
> +{
> + int ret;
> +
> + /* request core clock */
> + nfc->core_clk = devm_clk_get(nfc->dev, "core");
> + if (IS_ERR(nfc->core_clk)) {
> + dev_err(nfc->dev, "failed to get core clk\n");
> + return PTR_ERR(nfc->core_clk);
> + }
> +
> + nfc->device_clk = devm_clk_get(nfc->dev, "device");
> + if (IS_ERR(nfc->device_clk)) {
> + dev_err(nfc->dev, "failed to get device clk\n");
> + return PTR_ERR(nfc->device_clk);
> + }
> +
> + nfc->phase_tx = devm_clk_get(nfc->dev, "tx");
> + if (IS_ERR(nfc->phase_tx)) {
> + dev_err(nfc->dev, "failed to get tx clk\n");
> + return PTR_ERR(nfc->phase_tx);
> + }
> +
> + nfc->phase_rx = devm_clk_get(nfc->dev, "rx");
> + if (IS_ERR(nfc->phase_rx)) {
> + dev_err(nfc->dev, "failed to get rx clk\n");
> + return PTR_ERR(nfc->phase_rx);
> + }
> +
> + /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
> + regmap_update_bits(nfc->reg_clk,
> + 0, CLK_SELECT_NAND, CLK_SELECT_NAND);
> +
> + ret = clk_prepare_enable(nfc->core_clk);
> + if (ret) {
> + dev_err(nfc->dev, "failed to enable core clk\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(nfc->device_clk);
> + if (ret) {
> + dev_err(nfc->dev, "failed to enable device clk\n");
> + clk_disable_unprepare(nfc->core_clk);
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(nfc->phase_tx);
> + if (ret) {
> + dev_err(nfc->dev, "failed to enable tx clk\n");
> + clk_disable_unprepare(nfc->core_clk);
> + clk_disable_unprepare(nfc->device_clk);
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(nfc->phase_rx);
> + if (ret) {
> + dev_err(nfc->dev, "failed to enable rx clk\n");
> + clk_disable_unprepare(nfc->core_clk);
> + clk_disable_unprepare(nfc->device_clk);
> + clk_disable_unprepare(nfc->phase_tx);
This error case is a good candidate to a goto statement.
> + return ret;
> + }
> +
> + ret = clk_set_rate(nfc->device_clk, 24000000);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static void meson_nfc_disable_clk(struct meson_nfc *nfc)
> +{
> + clk_disable_unprepare(nfc->phase_rx);
> + clk_disable_unprepare(nfc->phase_tx);
> + clk_disable_unprepare(nfc->device_clk);
> + clk_disable_unprepare(nfc->core_clk);
> +}
> +
> +static void meson_nfc_free_buffer(struct nand_chip *nand)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> +
> + kfree(meson_chip->info_buf);
> + kfree(meson_chip->data_buf);
> +}
> +
> +static int meson_chip_buffer_init(struct nand_chip *nand)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + u32 page_bytes, info_bytes, nsectors;
> +
> + nsectors = mtd->writesize / nand->ecc.size;
> +
> + page_bytes = mtd->writesize + mtd->oobsize;
> + info_bytes = nsectors * PER_INFO_BYTE;
> +
> + meson_chip->data_buf = kmalloc(page_bytes, GFP_KERNEL);
> + if (!meson_chip->data_buf)
> + return -ENOMEM;
> +
> + meson_chip->info_buf = kmalloc(info_bytes, GFP_KERNEL);
> + if (!meson_chip->info_buf) {
> + kfree(meson_chip->data_buf);
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +static
> +int meson_nfc_setup_data_interface(struct nand_chip *nand, int csline,
> + const struct nand_data_interface *conf)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + const struct nand_sdr_timings *timings;
> + u32 div, bt_min, bt_max, tbers_clocks;
> +
> + timings = nand_get_sdr_timings(conf);
> + if (IS_ERR(timings))
> + return -ENOTSUPP;
> +
> + if (csline == NAND_DATA_IFACE_CHECK_ONLY)
> + return 0;
> +
> + div = DIV_ROUND_UP((timings->tRC_min / 1000), NFC_CLK_CYCLE);
> + bt_min = (timings->tREA_max + NFC_DEFAULT_DELAY) / div;
> + bt_max = (NFC_DEFAULT_DELAY + timings->tRHOH_min +
> + timings->tRC_min / 2) / div;
> +
> + meson_chip->twb = DIV_ROUND_UP(PSEC_TO_NSEC(timings->tWB_max),
> + div * NFC_CLK_CYCLE);
> + meson_chip->tadl = DIV_ROUND_UP(PSEC_TO_NSEC(timings->tADL_min),
> + div * NFC_CLK_CYCLE);
> + tbers_clocks = DIV_ROUND_UP(PSEC_TO_NSEC(timings->tBERS_max),
> + div * NFC_CLK_CYCLE);
> + meson_chip->tbers_max = ilog2(tbers_clocks);
> + if (!is_power_of_2(tbers_clocks))
> + meson_chip->tbers_max++;
> +
> + bt_min = DIV_ROUND_UP(bt_min, 1000);
> + bt_max = DIV_ROUND_UP(bt_max, 1000);
> +
> + if (bt_max < bt_min)
> + return -EINVAL;
> +
> + meson_chip->level1_divider = div;
> + meson_chip->clk_rate = 1000000000 / meson_chip->level1_divider;
> + meson_chip->bus_timing = (bt_min + bt_max) / 2 + 1;
> +
> + return 0;
> +}
> +
> +static int meson_nand_bch_mode(struct nand_chip *nand)
> +{
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + struct meson_nand_ecc meson_ecc[] = {
> + MESON_ECC_DATA(NFC_ECC_BCH8_1K, 8),
> + MESON_ECC_DATA(NFC_ECC_BCH24_1K, 24),
> + MESON_ECC_DATA(NFC_ECC_BCH30_1K, 30),
> + MESON_ECC_DATA(NFC_ECC_BCH40_1K, 40),
> + MESON_ECC_DATA(NFC_ECC_BCH50_1K, 50),
> + MESON_ECC_DATA(NFC_ECC_BCH60_1K, 60),
> + };
Maybe this array could be static?
> + int i;
> +
> + if (nand->ecc.strength > 60 || nand->ecc.strength < 8)
> + return -EINVAL;
> +
> + for (i = 0; i < sizeof(meson_ecc); i++) {
> + if (meson_ecc[i].strength == nand->ecc.strength) {
> + meson_chip->bch_mode = meson_ecc[i].bch;
> + return 0;
> + }
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int meson_nand_attach_chip(struct nand_chip *nand)
> +{
> + struct meson_nfc *nfc = nand_get_controller_data(nand);
> + struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + int nsectors = mtd->writesize / 1024;
> + int ret;
> +
> + if (!mtd->name) {
> + mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
> + "%s:nand%d",
> + dev_name(nfc->dev),
> + meson_chip->sels[0]);
> + if (!mtd->name)
> + return -ENOMEM;
> + }
> +
> + if (nand->bbt_options & NAND_BBT_USE_FLASH)
> + nand->bbt_options |= NAND_BBT_NO_OOB;
> +
> + nand->options |= NAND_NO_SUBPAGE_WRITE;
> +
> + ret = nand_ecc_choose_conf(nand, nfc->data->ecc_caps,
> + mtd->oobsize - 2 * nsectors);
> + if (ret) {
> + dev_err(nfc->dev, "failed to ecc init\n");
> + return -EINVAL;
> + }
> +
> + ret = meson_nand_bch_mode(nand);
> + if (ret)
> + return -EINVAL;
> +
> + nand->ecc.mode = NAND_ECC_HW;
> + nand->ecc.write_page_raw = meson_nfc_write_page_raw;
> + nand->ecc.write_page = meson_nfc_write_page_hwecc;
> + nand->ecc.write_oob_raw = nand_write_oob_std;
> + nand->ecc.write_oob = nand_write_oob_std;
> +
> + nand->ecc.read_page_raw = meson_nfc_read_page_raw;
> + nand->ecc.read_page = meson_nfc_read_page_hwecc;
> + nand->ecc.read_oob_raw = meson_nfc_read_oob_raw;
> + nand->ecc.read_oob = meson_nfc_read_oob;
> +
> + if (nand->options & NAND_BUSWIDTH_16) {
> + dev_err(nfc->dev, "16bits buswidth not supported");
> + return -EINVAL;
> + }
> + meson_chip_buffer_init(nand);
> + if (ret)
> + return -ENOMEM;
> +
> + return ret;
> +}
> +
> +static const struct nand_controller_ops meson_nand_controller_ops = {
> + .attach_chip = meson_nand_attach_chip,
Don't you need a ->detach_chip hook to free data_buf/info_buf
buffers?
> +};
> +
> +static int
> +meson_nfc_nand_chip_init(struct device *dev,
> + struct meson_nfc *nfc, struct device_node *np)
> +{
> + struct meson_nfc_nand_chip *meson_chip;
> + struct nand_chip *nand;
> + struct mtd_info *mtd;
> + int ret, i;
> + u32 tmp, nsels;
> +
> + if (!of_get_property(np, "reg", &nsels))
> + return -EINVAL;
> +
> + nsels /= sizeof(u32);
> + if (!nsels || nsels > MAX_CE_NUM) {
> + dev_err(dev, "invalid reg property size\n");
> + return -EINVAL;
> + }
> +
> + meson_chip = devm_kzalloc(dev,
> + sizeof(*meson_chip) + (nsels * sizeof(u8)),
> + GFP_KERNEL);
> + if (!meson_chip)
> + return -ENOMEM;
> +
> + meson_chip->nsels = nsels;
> +
> + for (i = 0; i < nsels; i++) {
> + ret = of_property_read_u32_index(np, "reg", i, &tmp);
> + if (ret) {
> + dev_err(dev, "could not retrieve reg property: %d\n",
> + ret);
> + return ret;
> + }
> +
> + if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
> + dev_err(dev, "CS %d already assigned\n", tmp);
> + return -EINVAL;
> + }
> + }
> +
> + nand = &meson_chip->nand;
> + nand->controller = &nfc->controller;
> + nand->controller->ops = &meson_nand_controller_ops;
> + nand_set_flash_node(nand, np);
> + nand_set_controller_data(nand, nfc);
> +
> + nand->options |= NAND_USE_BOUNCE_BUFFER;
> + nand->select_chip = meson_nfc_select_chip;
> + nand->exec_op = meson_nfc_exec_op;
> + nand->setup_data_interface = meson_nfc_setup_data_interface;
> + mtd = nand_to_mtd(nand);
> + mtd->owner = THIS_MODULE;
> + mtd->dev.parent = dev;
> +
> + ret = nand_scan(nand, nsels);
> + if (ret)
> + return ret;
> +
> + ret = mtd_device_register(mtd, NULL, 0);
> + if (ret) {
> + dev_err(dev, "failed to register mtd device: %d\n", ret);
> + nand_cleanup(nand);
> + return ret;
> + }
> +
> + list_add_tail(&meson_chip->node, &nfc->chips);
> +
> + return 0;
> +}
> +
> +static int meson_nfc_nand_chip_cleanup(struct meson_nfc *nfc)
> +{
> + struct meson_nfc_nand_chip *meson_chip;
> + struct mtd_info *mtd;
> + int ret;
> +
> + while (!list_empty(&nfc->chips)) {
> + meson_chip = list_first_entry(&nfc->chips,
> + struct meson_nfc_nand_chip, node);
> + mtd = nand_to_mtd(&meson_chip->nand);
> + ret = mtd_device_unregister(mtd);
> + if (ret)
> + return ret;
> +
> + meson_nfc_free_buffer(&meson_chip->nand);
> + nand_cleanup(&meson_chip->nand);
> + list_del(&meson_chip->node);
> + }
> +
> + return 0;
> +}
> +
> +static int meson_nfc_nand_chips_init(struct device *dev,
> + struct meson_nfc *nfc)
> +{
> + struct device_node *np = dev->of_node;
> + struct device_node *nand_np;
> + int ret;
> +
> + for_each_child_of_node(np, nand_np) {
> + ret = meson_nfc_nand_chip_init(dev, nfc, nand_np);
> + if (ret) {
> + meson_nfc_nand_chip_cleanup(nfc);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static irqreturn_t meson_nfc_irq(int irq, void *id)
> +{
> + struct meson_nfc *nfc = id;
> + u32 cfg;
> +
> + cfg = readl(nfc->reg_base + NFC_REG_CFG);
> + if (!(cfg & NFC_RB_IRQ_EN))
> + return IRQ_NONE;
> +
> + cfg &= ~(NFC_RB_IRQ_EN);
> + writel(cfg, nfc->reg_base + NFC_REG_CFG);
> +
> + complete(&nfc->completion);
> + return IRQ_HANDLED;
> +}
> +
> +static const struct meson_nfc_data meson_gxl_data = {
> + .ecc_caps = &meson_gxl_ecc_caps,
> +};
> +
> +static const struct meson_nfc_data meson_axg_data = {
> + .ecc_caps = &meson_axg_ecc_caps,
> +};
> +
> +static const struct of_device_id meson_nfc_id_table[] = {
> + {
> + .compatible = "amlogic,meson-gxl-nfc",
> + .data = &meson_gxl_data,
> + }, {
> + .compatible = "amlogic,meson-axg-nfc",
> + .data = &meson_axg_data,
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, meson_nfc_id_table);
> +
> +static int meson_nfc_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct meson_nfc *nfc;
> + struct resource *res;
> + int ret, irq;
> +
> + nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
> + if (!nfc)
> + return -ENOMEM;
> +
> + nfc->data = of_device_get_match_data(&pdev->dev);
> + if (!nfc->data)
> + return -ENODEV;
> +
> + nand_controller_init(&nfc->controller);
> + INIT_LIST_HEAD(&nfc->chips);
> +
> + nfc->dev = dev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + nfc->reg_base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(nfc->reg_base))
> + return PTR_ERR(nfc->reg_base);
> +
> + nfc->reg_clk =
> + syscon_regmap_lookup_by_phandle(dev->of_node,
> + "amlogic,mmc-syscon");
> + if (IS_ERR(nfc->reg_clk)) {
> + dev_err(dev, "Failed to lookup clock base\n");
> + return PTR_ERR(nfc->reg_clk);
> + }
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0) {
> + dev_err(dev, "no nfi irq resource\n");
> + return -EINVAL;
> + }
> +
> + ret = meson_nfc_clk_init(nfc);
> + if (ret) {
> + dev_err(dev, "failed to initialize nand clk\n");
> + goto err;
Useless goto, a return would be enough.
> + }
> +
> + writel(0, nfc->reg_base + NFC_REG_CFG);
> + ret = devm_request_irq(dev, irq, meson_nfc_irq, 0, dev_name(dev), nfc);
> + if (ret) {
> + dev_err(dev, "failed to request nfi irq\n");
> + ret = -EINVAL;
> + goto err_clk;
> + }
> +
> + ret = dma_set_mask(dev, DMA_BIT_MASK(32));
> + if (ret) {
> + dev_err(dev, "failed to set dma mask\n");
Nit: I prefer when acronyms are upper case in plain English (DMA, NAND,
IRQ, etc).
> + goto err_clk;
> + }
> +
> + platform_set_drvdata(pdev, nfc);
> +
> + ret = meson_nfc_nand_chips_init(dev, nfc);
> + if (ret) {
> + dev_err(dev, "failed to init nand chips\n");
> + goto err_clk;
> + }
> +
> + return 0;
> +
> +err_clk:
> + meson_nfc_disable_clk(nfc);
> +err:
This goto can be removed.
> + return ret;
> +}
> +
> +static int meson_nfc_remove(struct platform_device *pdev)
> +{
> + struct meson_nfc *nfc = platform_get_drvdata(pdev);
> + int ret;
> +
> + ret = meson_nfc_nand_chip_cleanup(nfc);
> + if (ret)
> + return ret;
> +
> + meson_nfc_disable_clk(nfc);
> +
> + platform_set_drvdata(pdev, NULL);
> +
> + return 0;
> +}
> +
> +static struct platform_driver meson_nfc_driver = {
> + .probe = meson_nfc_probe,
> + .remove = meson_nfc_remove,
> + .driver = {
> + .name = "meson-nand",
> + .of_match_table = meson_nfc_id_table,
> + },
> +};
> +module_platform_driver(meson_nfc_driver);
> +
> +MODULE_LICENSE("Dual MIT/GPL");
> +MODULE_AUTHOR("Liang Yang <liang.yang@amlogic.com>");
> +MODULE_DESCRIPTION("Amlogic's Meson NAND Flash Controller driver");
Thanks,
Miquèl
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 2/3] arm64: dts: allwinner: a64: Add A64 CSI controller
From: Michael Nazzareno Trimarchi @ 2018-12-07 9:16 UTC (permalink / raw)
To: Maxime Ripard
Cc: Mark Rutland, devicetree, LKML, Chen-Yu Tsai, Rob Herring,
Jagan Teki, linux-amarula, linux-arm-kernel
In-Reply-To: <20181207074723.l3ykhqojfkd4y4ie@flea>
Hi Maxime
On Fri, Dec 7, 2018 at 8:47 AM Maxime Ripard <maxime.ripard@bootlin.com> wrote:
>
> On Thu, Dec 06, 2018 at 06:07:59PM +0100, Michael Nazzareno Trimarchi wrote:
> > On Thu, Dec 6, 2018 at 4:34 PM Maxime Ripard <maxime.ripard@bootlin.com> wrote:
> > > On Thu, Dec 06, 2018 at 06:53:05PM +0530, Jagan Teki wrote:
> > > > Allwinner A64 CSI controller has similar features as like in
> > > > H3, So add support for A64 via H3 fallback.
> > > >
> > > > Also updated CSI_SCLK to use 300MHz via assigned-clocks, since
> > > > the default clock 600MHz seems unable to drive the sensor(ov5640)
> > > > to capture the image.
> > > >
> > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > > ---
> > > > Changes for v2:
> > > > - Use CSI_SCLK to 300MHz
> > > >
> > > > arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 23 +++++++++++++++++++
> > > > 1 file changed, 23 insertions(+)
> > > >
> > > > diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> > > > index 384c417cb7a2..d7ab0006ebce 100644
> > > > --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> > > > +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> > > > @@ -532,6 +532,12 @@
> > > > interrupt-controller;
> > > > #interrupt-cells = <3>;
> > > >
> > > > + csi_pins: csi-pins {
> > > > + pins = "PE0", "PE2", "PE3", "PE4", "PE5", "PE6",
> > > > + "PE7", "PE8", "PE9", "PE10", "PE11";
> > > > + function = "csi0";
> > > > + };
> > > > +
> > > > i2c0_pins: i2c0_pins {
> > > > pins = "PH0", "PH1";
> > > > function = "i2c0";
> > > > @@ -899,6 +905,23 @@
> > > > status = "disabled";
> > > > };
> > > >
> > > > + csi: csi@1cb0000 {
> > > > + compatible = "allwinner,sun50i-a64-csi",
> > > > + "allwinner,sun8i-h3-csi";
> > > > + reg = <0x01cb0000 0x1000>;
> > > > + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
> > > > + clocks = <&ccu CLK_BUS_CSI>,
> > > > + <&ccu CLK_CSI_SCLK>,
> > > > + <&ccu CLK_DRAM_CSI>;
> > > > + clock-names = "bus", "mod", "ram";
> > > > + resets = <&ccu RST_BUS_CSI>;
> > > > + pinctrl-names = "default";
> > > > + pinctrl-0 = <&csi_pins>;
> > > > + assigned-clocks = <&ccu CLK_CSI_SCLK>;
> > > > + assigned-clock-rates = <300000000>;
> > >
> > > That should be enforced in the driver.
> > >
> >
> > We are not really sure what is the best here. Our first idea was to
> > put in the board file and then Jagan
> > decide to put in dtsi. We don't have enough coverage of camera on this
> > CPU and I prefer to stay with this
> > minimal change that does not impact the driver.
>
> The thing is that:
> - in this commit log, you're stating that it depends on the sensor,
> which indicates that this would be a board level addition
> - In another patch series, Jagan reported IIRC that it actually
> depends on the resolution, so it doesn't belong in the DT at all
> - And then, you don't even have any guarantee on the clock rate. The
> sole guarantee you have is that when your driver will probe, the
> rate will be close to those 300MHz. That's it. It might completely
> change after the driver has probed, or be rounded to something
> else entirely, who knows.
I'm not so interested in the story but it's clear what you ask but in
short having one
sensor up to 5M pixel we can be sure where the reason is but make it
more pratical.
We have a parent clock that is the peripheral clock on clock
tree that run at 600Mhz. With a clock divider of 0 the driver work but
the acquisition
as problem on quality. Now the same sensor seems to work when the
logic is clocked
as half of the speed. If I remind in the right way the divider can be
only possible so
you can get pclk / (n + 1) without reparent to a different input.
Now I don't find any nice documentation that state that 600Mhz
is not supported but anyway, you suggest to do the same that is done
in fimc driver so
set there the rate there and offcourse x platform change like:
#define A64_CSI_FREQUENCY 600
ret = clk_set_rate(csk_core_clk, A64_CSI_FREQUENCY);
>
> So really, putting it in the DT is nothing but a hack.
>
Michael
> Maxime
>
> --
> Maxime Ripard, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
--
| Michael Nazzareno Trimarchi Amarula Solutions BV |
| COO - Founder Cruquiuskade 47 |
| +31(0)851119172 Amsterdam 1018 AM NL |
| [`as] http://www.amarulasolutions.com |
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 5/5] ARM: spectre-v2: per-CPU vtables to work around big.Little systems
From: Ard Biesheuvel @ 2018-12-07 9:11 UTC (permalink / raw)
To: Krzysztof Kozlowski, Russell King
Cc: Mark Rutland, Julien Thierry, Marc Zyngier, Will Deacon,
Qais.Yousef, linux-arm-kernel, Morten.Rasmussen, dietmar.eggemann,
Marek Szyprowski
In-Reply-To: <CAJKOXPdF7f+zhzfQ6tGtxkrgaz0GQfM6N-5LwymfoZozBgsELQ@mail.gmail.com>
On Thu, 6 Dec 2018 at 16:58, Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On Thu, 6 Dec 2018 at 16:31, Russell King - ARM Linux
> <linux@armlinux.org.uk> wrote:
> >
> > On Thu, Dec 06, 2018 at 04:03:27PM +0100, Krzysztof Kozlowski wrote:
> > > On Thu, 6 Dec 2018 at 15:37, Russell King - ARM Linux
> > > <linux@armlinux.org.uk> wrote:
> > > >
> > > > On Thu, Dec 06, 2018 at 03:30:22PM +0100, Krzysztof Kozlowski wrote:
> > > > > On Thu, 6 Dec 2018 at 15:07, Russell King - ARM Linux
> > > > > > That basically means that the dcache_clean_area method for CPU1
> > > > > > differs from the dcache_clean_area method for CPU0. If all your
> > > > > > CPUs are identical, that definitely should not be happening.
> > > > > >
> > > > > > Hmm. Interestingly, OMAP4430 passes hotplug tests just fine.
> > > > > >
> > > > > > Please try this patch.
> > > > >
> > > > > This fixes both hotplug and suspend to RAM. I was trying to narrow why
> > > > > the pointers to all processor functions differ. During first boot they
> > > > > were OK but it seems they were changed just before suspend.
> > > >
> > > > Thanks for testing. I think this is probably a better patch which
> > > > should end up with the same result.
> > > >
> > > > I suspect no one else has noticed because most people have big.Little
> > > > support disabled - that'd explain why it doesn't show up on OMAP4.
> > > >
> > > > diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
> > > > index 81d0efb055c6..44f9776139a8 100644
> > > > --- a/arch/arm/mm/proc-macros.S
> > > > +++ b/arch/arm/mm/proc-macros.S
> > > > @@ -274,6 +274,13 @@
> > > > .endm
> > > >
> > > > .macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0, bugs=0
> > > > +/*
> > > > + * If we are building for big.Little with branch predictor hardening,
> > > > + * we need the processor function tables to remain available after boot.
> > > > + */
> > > > +#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
> > > > + .rodata
> > > > +#endif
> > > > .type \name\()_processor_functions, #object
> > > > .align 2
> > > > ENTRY(\name\()_processor_functions)
> > > > @@ -309,6 +316,9 @@ ENTRY(\name\()_processor_functions)
> > > > .endif
> > > >
> > > > .size \name\()_processor_functions, . - \name\()_processor_functions
> > > > +#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
> > > > + .previous
> > > > +#endif
> > > > .endm
> > > >
> > > > .macro define_cache_functions name:req
Russell,
I noticed that the patch merged by Linus has
#if 1 // defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
Was that what you intended?
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 0/9] phy: Add configuration interface for MIPI D-PHY devices
From: Maxime Ripard @ 2018-12-07 9:09 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: Archit Taneja, Krzysztof Witos, Rafal Ciepiela, Boris Brezillon,
linux-kernel, dri-devel, Andrzej Hajda, Chen-Yu Tsai,
Laurent Pinchart, Thomas Petazzoni, linux-arm-kernel, linux-media
In-Reply-To: <f149ff50-b158-ef35-bf86-26d6b38c8068@ti.com>
[-- Attachment #1.1: Type: text/plain, Size: 1783 bytes --]
On Fri, Dec 07, 2018 at 10:30:55AM +0530, Kishon Vijay Abraham I wrote:
> Maxime,
>
> On 06/11/18 8:24 PM, Maxime Ripard wrote:
> > Hi,
> >
> > Here is a set of patches to allow the phy framework consumers to test and
> > apply runtime configurations.
> >
> > This is needed to support more phy classes that require tuning based on
> > parameters depending on the current use case of the device, in addition to
> > the power state management already provided by the current functions.
> >
> > A first test bed for that API are the MIPI D-PHY devices. There's a number
> > of solutions that have been used so far to support these phy, most of the
> > time being an ad-hoc driver in the consumer.
> >
> > That approach has a big shortcoming though, which is that this is quite
> > difficult to deal with consumers integrated with multiple variants of phy,
> > of multiple consumers integrated with the same phy.
> >
> > The latter case can be found in the Cadence DSI bridge, and the CSI
> > transceiver and receivers. All of them are integrated with the same phy, or
> > can be integrated with different phy, depending on the implementation.
> >
> > I've looked at all the MIPI DSI drivers I could find, and gathered all the
> > parameters I could find. The interface should be complete, and most of the
> > drivers can be converted in the future. The current set converts two of
> > them: the above mentionned Cadence DSI driver so that the v4l2 drivers can
> > use them, and the Allwinner MIPI-DSI driver.
>
> Are you planning to send one more revision of this series after fixing the
> comments?
I'll send a new version today.
Thanks!
Maxime
--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 1/3] arm64: dts: qcom: msm8998: correct xo clock name
From: Marc Gonzalez @ 2018-12-07 9:03 UTC (permalink / raw)
To: Stephen Boyd, Andy Gross
Cc: Jeffrey Hugo, MSM, Georgi Djakov, Linux ARM, Bjorn Andersson
In-Reply-To: <154412124335.88331.16092762627424651997@swboyd.mtv.corp.google.com>
On 06/12/2018 19:34, Stephen Boyd wrote:
> Quoting Jeffrey Hugo (2018-12-05 15:04:01)
>> On 12/5/2018 2:42 PM, Stephen Boyd wrote:
>>> Quoting Jeffrey Hugo (2018-12-05 13:20:07)
>>>> On 12/5/2018 2:04 PM, Stephen Boyd wrote:
>>>>> Quoting Jeffrey Hugo (2018-12-05 09:03:54)
>>>>>
>>>>> I don't quite understand the patch in general. The xo_board clk should
>>>>> always exist in DT and the fixed factor clk in GCC is there until the
>>>>> rpm clk driver can control the XO clk state vote for the kernel.
>>>>
>>>> Sorry, this wasn't apparent. It doesn't seem like this "requirement" is
>>>> captured anywhere.
>>>
>>> Agreed!
>>>
>>>>
>>>> As far as the SD clocks are concerned, they are defined in GCC, and
>>>> eventually have a root parent called "xo". "xo" isn't defined anywhere,
>>>> so the SD clocks can't really be used, and the hardware doesn't come up.
>>>> This patch "fixed" that, but I missed the link to the rpm driver that
>>>> Marc pointed out.
>>>
>>> Hmm ok. The SD DT node should just point to the xo_board clk for now and
>>> later on it can be changed to use the rpm clk when the rpm node is
>>> created.
>>>
>>>>
>>>>
>>>>>
>>>>> If anything, change the DT node to be named xo-board instead of xo_board
>>>>> because that matches DT naming schemes and then add a clock-output-names
>>>>> = "xo_board" property to it so that we keep the underscore.
>>>>
>>>> I see this now, and I agree with it, but then SD goes back to a broken
>>>> state because there is "xo" clock for GCC. Its not quite clear to me
>>>> how to make GCC (and thus SD) happy again with this change reverted/fixed.
>>>>
>>>> Bjorn mentioned offline he is going to take a look, but he has a few
>>>> other things on his plate first.
>>>>
>>>
>>> There is an XO clk created in drivers/clk/qcom/gcc-msm8996.c, we should
>>> do the same here until rpm can handle this. I'll pack this patch up and
>>> merge it to clk-next soon.
>>
>> Thanks. I pulled in the below change into my tree, and fixed up the DT
>> based on the discussion we had. SD works, and things look sane to me
>> per clk_summary in debugfs.
>>
>> Feel free to throw my tested-by on if you want.
>
> Thanks. I did so and merged it up to clk-next.
@Andy, don't you still need to revert 634da3307b083ee83eb9b377081fdfd6416a148a
("arm64: dts: qcom: msm8998: correct xo clock name") in for-next?
Regards.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: WIP: UFS on apq8098
From: Marc Gonzalez @ 2018-12-07 8:57 UTC (permalink / raw)
To: Evan Green
Cc: Jeffrey Hugo, MSM, Stephen Boyd, Bjorn Andersson, Andy Gross,
Nicolas Dechesne, Linux ARM
In-Reply-To: <CAE=gft7Pd5u4Axa1XNf+tSYC_awxT8VLNXfJg7820LA1z9RtZg@mail.gmail.com>
On 06/12/2018 17:45, Evan Green wrote:
> I'll throw my random thought into the hopper here. With one particular
> brand of UFS part on SDM845 we needed to make sure we banged on the
> ufs_reset pin before the device would re-initialize fully. My hunch
> says this is not your issue, but it can't hurt to make sure this is
> happening.
First of all, thanks for chiming in. I feel I'm close to making this work.
My UFSHC DT node defines:
resets = <&gcc GCC_UFS_BCR>;
reset-names = "rst";
If I'm not mistaken, the uhfhc driver should tickle the reset register?
Is the ufs_reset pin something different?
Regards.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v5 2/3] iommu/io-pgtable-arm-v7s: Request DMA32 memory, and improve debugging
From: Nicolas Boichat @ 2018-12-07 8:48 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Michal Hocko, Will Deacon, Levin Alexander, linux-mm,
Christoph Lameter, Huaisheng Ye, Joerg Roedel, hch, Yong Wu,
David Rientjes, yingjoe.chen, Vlastimil Babka, Tomasz Figa,
Mike Rapoport, Matthias Brugger, Joonsoo Kim,
linux-arm Mailing List, Robin Murphy, lkml, Pekka Enberg, iommu,
Andrew Morton, Mel Gorman
In-Reply-To: <20181207080551.GA15120@bombadil.infradead.org>
On Fri, Dec 7, 2018 at 4:05 PM Matthew Wilcox <willy@infradead.org> wrote:
>
> On Fri, Dec 07, 2018 at 02:16:19PM +0800, Nicolas Boichat wrote:
> > +#ifdef CONFIG_ZONE_DMA32
> > +#define ARM_V7S_TABLE_GFP_DMA GFP_DMA32
> > +#define ARM_V7S_TABLE_SLAB_CACHE SLAB_CACHE_DMA32
>
> This name doesn't make any sense. Why not ARM_V7S_TABLE_SLAB_FLAGS ?
Sure, will fix in v6 then.
> > +#else
> > +#define ARM_V7S_TABLE_GFP_DMA GFP_DMA
> > +#define ARM_V7S_TABLE_SLAB_CACHE SLAB_CACHE_DMA
>
> Can you remind me again why it is, on machines which don't support
> ZONE_DMA32, why we have to allocate from ZONE_DMA? My understanding
> is that 64-bit machines have ZONE_DMA32 and 32-bit machines don't.
> So shouldn't this rather be GFP_KERNEL?
Sorry I mean to reply on the v4 thread, Christoph raised the same
question (https://patchwork.kernel.org/patch/10713025/).
I don't know, and I don't have all the hardware needed to test this
,-( Robin and Will both didn't seem sure.
I'd rather not introduce a new regression, this patch series tries to
fix a known arm64 regression, where we _need_ tables to be in DMA32.
If we want to change 32-bit hardware to use GFP_KERNEL, and we're sure
it works, that's fine by me, but it should be in another patch set.
Hope this makes sense,
Thanks,
> Actually, maybe we could centralise this in gfp.h:
>
> #ifdef CONFIG_64BIT
> # ifdef CONFIG_ZONE_DMA32
> #define GFP_32BIT GFP_DMA32
> # else
> #define GFP_32BIT GFP_DMA
> #else /* 32-bit */
> #define GFP_32BIT GFP_KERNEL
> #endif
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] dt-bindings: rtc: sun6i-rtc: Fix register range in example
From: Chen-Yu Tsai @ 2018-12-07 8:47 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni, Maxime Ripard, Rob Herring,
Mark Rutland
Cc: linux-rtc, devicetree, Chen-Yu Tsai, linux-kernel,
linux-arm-kernel
The register range for the RTC extends beyond 0x54.
Use the size from the user manual's memory map instead.
Fixes: 9765d2d94309 ("rtc: sun6i: Add sun6i RTC driver")
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Documentation/devicetree/bindings/rtc/sun6i-rtc.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
index ceb38abf1ea2..6b732c41392b 100644
--- a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
+++ b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
@@ -38,7 +38,7 @@ Example:
rtc: rtc@1f00000 {
compatible = "allwinner,sun6i-a31-rtc";
- reg = <0x01f00000 0x54>;
+ reg = <0x01f00000 0x400>;
interrupts = <0 40 4>, <0 41 4>;
clock-output-names = "osc32k";
clocks = <&ext_osc32k>;
--
2.20.0.rc1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 1/2] arm64: dts: ti: k3-am654: Add Support for MMC/SD
From: Faiz Abbas @ 2018-12-07 8:42 UTC (permalink / raw)
To: linux-kernel, devicetree, linux-arm-kernel
Cc: mark.rutland, nm, ulf.hansson, adrian.hunter, kishon, t-kristo,
robh+dt, faiz_abbas, michal.simek
In-Reply-To: <20181207084233.13700-1-faiz_abbas@ti.com>
There are two MMC host controller instances present on the TI's
Am654 SOCs. Add device tree nodes for the same.
Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 28 ++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
index 916434839603..d07212f16a81 100644
--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
@@ -129,4 +129,32 @@
clocks = <&k3_clks 113 1>;
power-domains = <&k3_pds 113>;
};
+
+ sdhci0: sdhci@4f80000 {
+ compatible = "ti,am654-sdhci-5.1";
+ reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
+ power-domains = <&k3_pds 47>;
+ clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
+ clock-names = "clk_ahb", "clk_xin";
+ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ sdhci-caps-mask = <0x80000007 0x0>;
+ mmc-ddr-1_8v;
+ ti,otap-del-sel = <0x2>;
+ ti,trm-icp = <0x8>;
+ status = "disabled";
+ };
+
+ sdhci1: sdhci@4fa0000 {
+ compatible = "ti,am654-sdhci-5.1";
+ reg = <0x0 0x4fa0000 0x0 0x260>, <0x0 0x4fb0000 0x0 0x134>;
+ power-domains = <&k3_pds 48>;
+ clocks = <&k3_clks 48 0>, <&k3_clks 48 1>;
+ clock-names = "clk_ahb", "clk_xin";
+ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+ sdhci-caps-mask = <0x80000007 0x0>;
+ mmc-ddr-1_8v;
+ ti,otap-del-sel = <0x2>;
+ ti,trm-icp = <0x8>;
+ status = "disabled";
+ };
};
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/2] arm64: dts: ti: k3-am654-base-board: Add MMC/SD support
From: Faiz Abbas @ 2018-12-07 8:42 UTC (permalink / raw)
To: linux-kernel, devicetree, linux-arm-kernel
Cc: mark.rutland, nm, ulf.hansson, adrian.hunter, kishon, t-kristo,
robh+dt, faiz_abbas, michal.simek
In-Reply-To: <20181207084233.13700-1-faiz_abbas@ti.com>
On the am654x-evm, sdhci0 node is connected to an eMMC while sdhci1
is connected to an SD card slot. Add nodes and pinmuxes for the same.
Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
.../arm64/boot/dts/ti/k3-am654-base-board.dts | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
index bd5a0069191d..5dcd16b787eb 100644
--- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts
@@ -60,6 +60,36 @@
AM65X_IOPAD(0x0070, PIN_INPUT, 5) /* (R25) GPMC0_CSn2.I2C2_SDA */
>;
};
+
+ main_mmc0_pins_default: main_mmc0_pins_default {
+ pinctrl-single,pins = <
+ AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */
+ AM65X_IOPAD(0x01ac, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */
+ AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */
+ AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */
+ AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */
+ AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */
+ AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */
+ AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */
+ AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */
+ AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */
+ AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */
+ AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
+ >;
+ };
+
+ main_mmc1_pins_default: main_mmc1_pins_default {
+ pinctrl-single,pins = <
+ AM65X_IOPAD(0x02d4, PIN_INPUT_PULLDOWN, 0) /* (C27) MMC1_CLK */
+ AM65X_IOPAD(0x02d8, PIN_INPUT_PULLUP, 0) /* (C28) MMC1_CMD */
+ AM65X_IOPAD(0x02d0, PIN_INPUT_PULLUP, 0) /* (D28) MMC1_DAT0 */
+ AM65X_IOPAD(0x02cc, PIN_INPUT_PULLUP, 0) /* (E27) MMC1_DAT1 */
+ AM65X_IOPAD(0x02c8, PIN_INPUT_PULLUP, 0) /* (D26) MMC1_DAT2 */
+ AM65X_IOPAD(0x02c4, PIN_INPUT_PULLUP, 0) /* (D27) MMC1_DAT3 */
+ AM65X_IOPAD(0x02dc, PIN_INPUT_PULLUP, 0) /* (B24) MMC1_SDCD */
+ AM65X_IOPAD(0x02e0, PIN_INPUT, 0) /* (C24) MMC1_SDWP */
+ >;
+ };
};
&main_pmx1 {
@@ -125,3 +155,19 @@
pinctrl-0 = <&main_i2c2_pins_default>;
clock-frequency = <400000>;
};
+
+&sdhci0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_mmc0_pins_default>;
+ bus-width = <8>;
+ non-removable;
+ ti,driver-strength-ohm = <50>;
+};
+
+&sdhci1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_mmc1_pins_default>;
+ ti,driver-strength-ohm = <50>;
+};
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 0/2] Add DT Support for MMCSD in Am65x-evm
From: Faiz Abbas @ 2018-12-07 8:42 UTC (permalink / raw)
To: linux-kernel, devicetree, linux-arm-kernel
Cc: mark.rutland, nm, ulf.hansson, adrian.hunter, kishon, t-kristo,
robh+dt, faiz_abbas, michal.simek
The following patches add dt support for MMCSD on the AM65x-evm.
THe series depends on driver support[1] and pinmux support[2] posted
separately.
[1] https://patchwork.kernel.org/project/linux-mmc/list/?series=53185
[2] https://lore.kernel.org/patchwork/project/lkml/list/?series=372649
Faiz Abbas (2):
arm64: dts: ti: k3-am654: Add Support for MMC/SD
arm64: dts: ti: k3-am654-base-board: Add MMC\SD support
arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 28 +++++++++++
.../arm64/boot/dts/ti/k3-am654-base-board.dts | 46 +++++++++++++++++++
2 files changed, 74 insertions(+)
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 2/2] arm64: uaccess: Implement unsafe accessors
From: Julien Thierry @ 2018-12-07 8:38 UTC (permalink / raw)
To: Catalin Marinas
Cc: peterz, will.deacon, linux-kernel, mingo, james.morse, hpa,
linux-arm-kernel
In-Reply-To: <20181206182551.GB37411@arrakis.emea.arm.com>
On 12/06/2018 06:25 PM, Catalin Marinas wrote:
> On Mon, Dec 03, 2018 at 01:55:18PM +0000, Julien Thierry wrote:
>> diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
>> index 07c3408..cabfcae 100644
>> --- a/arch/arm64/include/asm/uaccess.h
>> +++ b/arch/arm64/include/asm/uaccess.h
>> @@ -233,6 +233,23 @@ static inline void uaccess_enable_not_uao(void)
>> __uaccess_enable(ARM64_ALT_PAN_NOT_UAO);
>> }
>>
>> +#define unsafe_user_region_active uaccess_region_active
>> +static inline bool uaccess_region_active(void)
>> +{
>> + if (system_uses_ttbr0_pan()) {
>> + u64 ttbr;
>> +
>> + ttbr = read_sysreg(ttbr1_el1);
>> + return ttbr & TTBR_ASID_MASK;
>
> Nitpick: could write this in 1-2 lines.
>
True, I can do that in 1 line.
>> + } else if (cpus_have_const_cap(ARM64_ALT_PAN_NOT_UAO)) {
>> + return (read_sysreg(sctlr_el1) & SCTLR_EL1_SPAN) ?
>> + false :
>> + !read_sysreg_s(SYS_PSTATE_PAN);
>> + }
>
> ARM64_ALT_PAN_NOT_UAO implies ARM64_HAS_PAN which implies SCTLR_EL1.SPAN
> is 0 at run-time. Is this to cope with the case of being called prior to
> cpu_enable_pan()?
>
Yes, the issue I can into is that for cpufeatures, .cpu_enable()
callbacks are called inside stop_machine() which obviously might_sleep
and so attempts to check whether user_access is on. But for features
that get enabled before PAN, the PAN bit will be set.
Thanks,
Julien
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/3] arm64: defconfig: Enable scu-simple-card driver
From: Geert Uytterhoeven @ 2018-12-07 8:28 UTC (permalink / raw)
To: Simon Horman; +Cc: Linux-Renesas, Magnus Damm, Linux ARM
In-Reply-To: <595096daf0ac9c1741b6182eb72d636802a21006.1544126077.git.horms+renesas@verge.net.au>
Hi Simon,
On Thu, Dec 6, 2018 at 10:58 PM Simon Horman <horms+renesas@verge.net.au> wrote:
> Enable the scu-simple-card which is used by
> the R-Car E3 (r8a77990) based Ebisu board.
>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> ---
> arch/arm64/configs/defconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
> index f88190463481..9d0b42d96f03 100644
> --- a/arch/arm64/configs/defconfig
> +++ b/arch/arm64/configs/defconfig
> @@ -491,6 +491,7 @@ CONFIG_SND_SOC_RT5514=m
> CONFIG_SND_SOC_RT5514_SPI=m
> CONFIG_SND_SOC_RT5645=m
> CONFIG_SND_SIMPLE_CARD=m
> +CONFIG_SND_SIMPLE_SCU_CARD=y
Shouldn't this be "m"?
> CONFIG_SND_AUDIO_GRAPH_CARD=m
> CONFIG_I2C_HID=m
> CONFIG_USB=y
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] soc: fsl: guts: us devm_kstrdup_const() for RO data
From: Nicholas Mc Guire @ 2018-12-07 8:22 UTC (permalink / raw)
To: Li Yang; +Cc: linuxppc-dev, linux-kernel, linux-arm-kernel, Nicholas Mc Guire
devm_kstrdup() may return NULL if internal allocation failed, but
as machine is from the device tree, and thus RO, devm_kstrdup_const()
can be used here, which will only copy the reference.
Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Fixes: a6fc3b698130 ("soc: fsl: add GUTS driver for QorIQ platforms")
---
Problem located by experimental coccinelle script
Patch was compile tested with: multi_v7_defconfig (implies FSL_GUTS=y)
Patch is against 4.20-rc5 (localversion-next is next-20181207)
drivers/soc/fsl/guts.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 302e0c8..15071ec 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -157,7 +157,8 @@ static int fsl_guts_probe(struct platform_device *pdev)
of_property_read_string_index(root, "compatible", 0, &machine);
of_node_put(root);
if (machine)
- soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
+ soc_dev_attr.machine = devm_kstrdup_const(dev, machine,
+ GFP_KERNEL);
svr = fsl_guts_get_svr();
soc_die = fsl_soc_die_match(svr, fsl_soc_die);
--
2.1.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 1/5] dt-bindings: nvmem: add binding for Raspberry Pi OTP
From: Stefan Wahren @ 2018-12-07 8:10 UTC (permalink / raw)
To: Rob Herring
Cc: Mark Rutland, devicetree, Florian Fainelli, Arnd Bergmann,
Scott Branden, Ray Jui, Eric Anholt, Srinivas Kandagatla,
linux-rpi-kernel, gregkh, bcm-kernel-feedback-list,
linux-arm-kernel
In-Reply-To: <20181206234941.GA6340@bogus>
Hi Rob,
Am 07.12.18 um 00:49 schrieb Rob Herring:
> On Wed, Nov 21, 2018 at 02:11:40PM +0100, Stefan Wahren wrote:
>> This patch adds the devicetree binding for Raspberry Pi customer OTP
>> driver.
>>
>> Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
>> ---
>> .../nvmem/raspberrypi,bcm2835-customer-otp.txt | 22 ++++++++++++++++++++++
>> 1 file changed, 22 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/nvmem/raspberrypi,bcm2835-customer-otp.txt
>>
>> diff --git a/Documentation/devicetree/bindings/nvmem/raspberrypi,bcm2835-customer-otp.txt b/Documentation/devicetree/bindings/nvmem/raspberrypi,bcm2835-customer-otp.txt
>> new file mode 100644
>> index 0000000..041ff17
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/nvmem/raspberrypi,bcm2835-customer-otp.txt
>> @@ -0,0 +1,22 @@
>> +Customer OTP Memory for Raspberry Pi
>> +
>> +The VC4 firmware exposes a mailbox interface that allows the ARM core
>> +to access the customer part of the OTP memory.
>> +
>> +The OTP node must be a child node of the Raspberry Pi firmware node.
>> +
>> +Required properties :
>> +- compatible : Should be "raspberrypi,bcm2835-customer-otp"
> Why do we need this child node? Can't the parent instantiate this?
>
> Are there OTP fields you want to expose in DT?
the customer part of the OTP is reserved (initialized with zero) for
user who wants to use the Raspberry Pi (mostly the Compute Module) in
their custom designs. So i cannot provide any nvmem cells yet because it
is up to the user to define them (e.g. hardware related values like
serial numbers, MAC addresses for additional network interfaces or
calibration values). But yes i consider the binding and the ability to
define nvmem cells via devicetree as a great feature.
Currently the Foundation suggests to use the mailbox interface from
userspace [1], but i prefer a more common way like nvmem.
[1] -
https://www.raspberrypi.org/documentation/hardware/industrial/README.md
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 0/3] Add driver Support for MMCSD on AM654x
From: Faiz Abbas @ 2018-12-07 8:11 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, devicetree, linux-mmc
Cc: mark.rutland, ulf.hansson, adrian.hunter, kishon, robh+dt,
faiz_abbas, michal.simek
The following patches add driver support for MMCSD on TI's AM654
platforms.
Previously I had added the support to sdhci-of-arasan driver with
a separate phy driver[1]. Since then it has turned out that tuning
operation (for HS200, HS400 and SDR104 speed modes) will require
configuration of phy registers. This completely breaks the model of
the sdhci-of-arasan driver which relies on a separate driver to
configure the phy register space.
Because of this, I am creating a new driver with both the sdhci and
phy register spaces. This helps me use the phy registers in a future
patch that adds tuning support.
DT patches will be posted in a separate series.
Changes in v2:
1. Reset OTAP delay back to default value in init.
2. Improved patch description for patch 2.
3. Minor style fixes.
[1] driver and phy patches posted before
https://patchwork.kernel.org/project/linux-mmc/list/?series=26623
Faiz Abbas (3):
dt-bindings: mmc: sdhci-am654: Document bindings for the host
controllers on TI's AM654 SOCs
dt-bindings: mmc: sdhci-of-arasan: Add deprecated message for am65
mmc: sdhci_am654: Add Initial Support for AM654 SDHCI driver
.../devicetree/bindings/mmc/arasan,sdhci.txt | 4 +
.../devicetree/bindings/mmc/sdhci-am654.txt | 37 ++
drivers/mmc/host/Kconfig | 12 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-arasan.c | 46 ---
drivers/mmc/host/sdhci_am654.c | 381 ++++++++++++++++++
6 files changed, 435 insertions(+), 46 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-am654.txt
create mode 100644 drivers/mmc/host/sdhci_am654.c
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 1/3] dt-bindings: mmc: sdhci-am654: Document bindings for the host controllers on TI's AM654 SOCs
From: Faiz Abbas @ 2018-12-07 8:11 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, devicetree, linux-mmc
Cc: mark.rutland, ulf.hansson, adrian.hunter, kishon, robh+dt,
faiz_abbas, michal.simek
In-Reply-To: <20181207081119.29162-1-faiz_abbas@ti.com>
Add binding documentation for mmc host controllers present on TI's AM654
SOCs.
Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
.../devicetree/bindings/mmc/sdhci-am654.txt | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-am654.txt
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-am654.txt b/Documentation/devicetree/bindings/mmc/sdhci-am654.txt
new file mode 100644
index 000000000000..862b93051bfe
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-am654.txt
@@ -0,0 +1,37 @@
+Device Tree Bindings for the SDHCI Controllers present on TI's AM654 SOCs
+
+The bindings follow the mmc[1], clock[2] and interrupt[3] bindings.
+Only deviations are documented here.
+
+ [1] Documentation/devicetree/bindings/mmc/mmc.txt
+ [2] Documentation/devicetree/bindings/clock/clock-bindings.txt
+ [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+Required Properties:
+ - compatible: should be "ti,am654-sdhci-5.1"
+ - reg: Must be two entries.
+ - The first should be the sdhci register space
+ - The second should the subsystem/phy register space
+ - clocks: Handles to the clock inputs.
+ - clock-names: Tuple including "clk_xin" and "clk_ahb"
+ - interrupts: Interrupt specifiers
+ - ti,otap-del-sel: Output Tap Delay select
+ - ti,trm-icp: DLL trim select
+ - ti,driver-strength-ohm: driver strength in ohms.
+ Valid values are 33, 40, 50, 66 and 100 ohms.
+
+Example:
+
+ sdhci0: sdhci@4f80000 {
+ compatible = "ti,am654-sdhci-5.1";
+ reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
+ power-domains = <&k3_pds 47>;
+ clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
+ clock-names = "clk_ahb", "clk_xin";
+ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ sdhci-caps-mask = <0x80000007 0x0>;
+ mmc-ddr-1_8v;
+ ti,otap-del-sel = <0x2>;
+ ti,trm-icp = <0x8>;
+ status = "disabled";
+ };
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 3/3] mmc: sdhci_am654: Add Initial Support for AM654 SDHCI driver
From: Faiz Abbas @ 2018-12-07 8:11 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, devicetree, linux-mmc
Cc: mark.rutland, ulf.hansson, adrian.hunter, kishon, robh+dt,
faiz_abbas, michal.simek
In-Reply-To: <20181207081119.29162-1-faiz_abbas@ti.com>
The host controllers on TI's AM654 SOCs are not compatible with
the phy and consumer model of the sdhci-of-arasan driver. It turns out
that for optimal operation at higher speeds, a special tuning procedure
needs to be implemented which involves configuration of platform
specific phy registers.
Therefore, branch out to a new sdhci_am654 driver and add the phy
register space with all phy configurations to it. Populate AM654
specific callbacks to sdhci_ops and add SDHCI_QUIRKS wherever
applicable.
Only add support for upto High Speed for SD card and upto DDR52 speed
mode for eMMC. Higher speeds will be added in subsequent patches.
Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
drivers/mmc/host/Kconfig | 12 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-arasan.c | 46 ----
drivers/mmc/host/sdhci_am654.c | 381 +++++++++++++++++++++++++++++
4 files changed, 394 insertions(+), 46 deletions(-)
create mode 100644 drivers/mmc/host/sdhci_am654.c
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 1b58739d9744..cfb2eb1a2c32 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -977,3 +977,15 @@ config MMC_SDHCI_OMAP
If you have a controller with this interface, say Y or M here.
If unsure, say N.
+
+config MMC_SDHCI_AM654
+ tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
+ depends on MMC_SDHCI_PLTFM && OF
+ help
+ This selects the Secure Digital Host Controller Interface (SDHCI)
+ support present in TI's AM654 SOCs. The controller supports
+ SD/MMC/SDIO devices.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 720d37777098..5c7770edc431 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
+obj-$(CONFIG_MMC_SDHCI_AM654) += sdhci_am654.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_MTK) += mtk-sd.o
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 142c4b802f31..c9e3e050ccc8 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -231,25 +231,6 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
}
}
-static void sdhci_arasan_am654_set_clock(struct sdhci_host *host,
- unsigned int clock)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
-
- if (sdhci_arasan->is_phy_on) {
- phy_power_off(sdhci_arasan->phy);
- sdhci_arasan->is_phy_on = false;
- }
-
- sdhci_set_clock(host, clock);
-
- if (clock > PHY_CLK_TOO_SLOW_HZ) {
- phy_power_on(sdhci_arasan->phy);
- sdhci_arasan->is_phy_on = true;
- }
-}
-
static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
@@ -335,29 +316,6 @@ static struct sdhci_arasan_of_data sdhci_arasan_data = {
.pdata = &sdhci_arasan_pdata,
};
-static const struct sdhci_ops sdhci_arasan_am654_ops = {
- .set_clock = sdhci_arasan_am654_set_clock,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
- .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
- .set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_arasan_reset,
- .set_uhs_signaling = sdhci_set_uhs_signaling,
-};
-
-static const struct sdhci_pltfm_data sdhci_arasan_am654_pdata = {
- .ops = &sdhci_arasan_am654_ops,
- .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
- SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
- SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
- .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
- SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
- SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
-};
-
-static const struct sdhci_arasan_of_data sdhci_arasan_am654_data = {
- .pdata = &sdhci_arasan_am654_pdata,
-};
-
static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
{
int cmd_error = 0;
@@ -520,10 +478,6 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
.compatible = "rockchip,rk3399-sdhci-5.1",
.data = &sdhci_arasan_rk3399_data,
},
- {
- .compatible = "ti,am654-sdhci-5.1",
- .data = &sdhci_arasan_am654_data,
- },
/* Generic compatible below here */
{
.compatible = "arasan,sdhci-8.9a",
diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
new file mode 100644
index 000000000000..6983438a45d0
--- /dev/null
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sdhci_am654.c - SDHCI driver for TI's AM654 SOCs
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ *
+ */
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include "sdhci-pltfm.h"
+
+/* CTL_CFG Registers */
+#define CTL_CFG_2 0x14
+
+#define SLOTTYPE_MASK GENMASK(31, 30)
+#define SLOTTYPE_EMBEDDED BIT(30)
+
+/* PHY Registers */
+#define PHY_CTRL1 0x100
+#define PHY_CTRL2 0x104
+#define PHY_CTRL3 0x108
+#define PHY_CTRL4 0x10C
+#define PHY_CTRL5 0x110
+#define PHY_CTRL6 0x114
+#define PHY_STAT1 0x130
+#define PHY_STAT2 0x134
+
+#define IOMUX_ENABLE_SHIFT 31
+#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT)
+#define OTAPDLYENA_SHIFT 20
+#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT)
+#define OTAPDLYSEL_SHIFT 12
+#define OTAPDLYSEL_MASK GENMASK(15, 12)
+#define STRBSEL_SHIFT 24
+#define STRBSEL_MASK GENMASK(27, 24)
+#define SEL50_SHIFT 8
+#define SEL50_MASK BIT(SEL50_SHIFT)
+#define SEL100_SHIFT 9
+#define SEL100_MASK BIT(SEL100_SHIFT)
+#define DLL_TRIM_ICP_SHIFT 4
+#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
+#define DR_TY_SHIFT 20
+#define DR_TY_MASK GENMASK(22, 20)
+#define ENDLL_SHIFT 1
+#define ENDLL_MASK BIT(ENDLL_SHIFT)
+#define DLLRDY_SHIFT 0
+#define DLLRDY_MASK BIT(DLLRDY_SHIFT)
+#define PDB_SHIFT 0
+#define PDB_MASK BIT(PDB_SHIFT)
+#define CALDONE_SHIFT 1
+#define CALDONE_MASK BIT(CALDONE_SHIFT)
+#define RETRIM_SHIFT 17
+#define RETRIM_MASK BIT(RETRIM_SHIFT)
+
+#define DRIVER_STRENGTH_50_OHM 0x0
+#define DRIVER_STRENGTH_33_OHM 0x1
+#define DRIVER_STRENGTH_66_OHM 0x2
+#define DRIVER_STRENGTH_100_OHM 0x3
+#define DRIVER_STRENGTH_40_OHM 0x4
+
+#define CLOCK_TOO_SLOW_HZ 400000
+
+static struct regmap_config sdhci_am654_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .fast_io = true,
+};
+
+struct sdhci_am654_data {
+ struct regmap *base;
+ struct clk *clk_ahb;
+ int otap_del_sel;
+ int trm_icp;
+ int drv_strength;
+ bool dll_on;
+};
+
+static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+ int sel50, sel100;
+ u32 mask, val;
+ int ret;
+
+ if (sdhci_am654->dll_on) {
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ ENDLL_MASK, 0);
+
+ sdhci_am654->dll_on = false;
+ }
+
+ sdhci_set_clock(host, clock);
+
+ if (clock > CLOCK_TOO_SLOW_HZ) {
+ /* Setup DLL Output TAP delay */
+ mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+ val = (1 << OTAPDLYENA_SHIFT) |
+ (sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
+ mask, val);
+ switch (clock) {
+ case 200000000:
+ sel50 = 0;
+ sel100 = 0;
+ break;
+ case 100000000:
+ sel50 = 0;
+ sel100 = 1;
+ break;
+ default:
+ sel50 = 1;
+ sel100 = 0;
+ }
+
+ /* Configure PHY DLL frequency */
+ mask = SEL50_MASK | SEL100_MASK;
+ val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
+ mask, val);
+ /* Configure DLL TRIM */
+ mask = DLL_TRIM_ICP_MASK;
+ val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT;
+
+ /* Configure DLL driver strength */
+ mask |= DR_TY_MASK;
+ val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ mask, val);
+ /* Enable DLL */
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ ENDLL_MASK, 0x1 << ENDLL_SHIFT);
+ /*
+ * Poll for DLL ready. Use a one second timeout.
+ * Works in all experiments done so far
+ */
+ ret = regmap_read_poll_timeout(sdhci_am654->base,
+ PHY_STAT1, val,
+ val & DLLRDY_MASK,
+ 1000, 1000000);
+
+ sdhci_am654->dll_on = true;
+ }
+}
+
+static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+ if (!IS_ERR(host->mmc->supply.vmmc)) {
+ struct mmc_host *mmc = host->mmc;
+
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+ }
+ sdhci_set_power_noreg(host, mode, vdd);
+}
+
+struct sdhci_ops sdhci_am654_ops = {
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_bus_width = sdhci_set_bus_width,
+ .set_power = sdhci_am654_set_power,
+ .set_clock = sdhci_am654_set_clock,
+ .reset = sdhci_reset,
+};
+
+static const struct sdhci_pltfm_data sdhci_am654_pdata = {
+ .ops = &sdhci_am654_ops,
+ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+ SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static int sdhci_am654_init(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+ u32 ctl_cfg_2 = 0;
+ u32 mask;
+ u32 val;
+ int ret;
+
+ /* Reset OTAP to default value */
+ mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
+ mask, 0x0);
+
+ regmap_read(sdhci_am654->base, PHY_STAT1, &val);
+ if (~val & CALDONE_MASK) {
+ /* Calibrate IO lines */
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ PDB_MASK, PDB_MASK);
+ ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
+ val, val & CALDONE_MASK, 1, 20);
+ if (ret)
+ return ret;
+ }
+
+ /* Enable pins by setting IO mux to 0 */
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ IOMUX_ENABLE_MASK, 0);
+
+ /* Set slot type based on SD or eMMC */
+ if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+ ctl_cfg_2 = SLOTTYPE_EMBEDDED;
+
+ regmap_update_bits(sdhci_am654->base, CTL_CFG_2,
+ ctl_cfg_2, SLOTTYPE_MASK);
+
+ return sdhci_add_host(host);
+}
+
+static int sdhci_am654_get_of_property(struct platform_device *pdev,
+ struct sdhci_am654_data *sdhci_am654)
+{
+ struct device *dev = &pdev->dev;
+ int drv_strength;
+ int ret;
+
+ ret = device_property_read_u32(dev, "ti,trm-icp",
+ &sdhci_am654->trm_icp);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u32(dev, "ti,otap-del-sel",
+ &sdhci_am654->otap_del_sel);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
+ &drv_strength);
+ if (ret)
+ return ret;
+
+ switch (drv_strength) {
+ case 50:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
+ break;
+ case 33:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
+ break;
+ case 66:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
+ break;
+ case 100:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
+ break;
+ case 40:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
+ break;
+ default:
+ dev_err(dev, "Invalid driver strength\n");
+ return -EINVAL;
+ }
+
+ sdhci_get_of_property(pdev);
+
+ return 0;
+}
+
+static int sdhci_am654_probe(struct platform_device *pdev)
+{
+ struct sdhci_pltfm_host *pltfm_host;
+ struct sdhci_am654_data *sdhci_am654;
+ struct sdhci_host *host;
+ struct resource *res;
+ struct clk *clk_xin;
+ struct device *dev = &pdev->dev;
+ void __iomem *base;
+ int ret;
+
+ host = sdhci_pltfm_init(pdev, &sdhci_am654_pdata, sizeof(*sdhci_am654));
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ pltfm_host = sdhci_priv(host);
+ sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+
+ clk_xin = devm_clk_get(dev, "clk_xin");
+ if (IS_ERR(clk_xin)) {
+ dev_err(dev, "clk_xin clock not found.\n");
+ ret = PTR_ERR(clk_xin);
+ goto err_pltfm_free;
+ }
+
+ sdhci_am654->clk_ahb = devm_clk_get(dev, "clk_ahb");
+ if (IS_ERR(sdhci_am654->clk_ahb)) {
+ dev_err(dev, "clk_ahb clock not found.\n");
+ ret = PTR_ERR(sdhci_am654->clk_ahb);
+ goto err_pltfm_free;
+ }
+
+ pltfm_host->clk = clk_xin;
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ goto pm_runtime_disable;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
+ goto pm_runtime_put;
+ }
+
+ sdhci_am654->base = devm_regmap_init_mmio(dev, base,
+ &sdhci_am654_regmap_config);
+ if (IS_ERR(sdhci_am654->base)) {
+ dev_err(dev, "Failed to initialize regmap\n");
+ ret = PTR_ERR(sdhci_am654->base);
+ goto pm_runtime_put;
+ }
+
+ ret = sdhci_am654_get_of_property(pdev, sdhci_am654);
+ if (ret)
+ goto pm_runtime_put;
+
+ ret = mmc_of_parse(host->mmc);
+ if (ret) {
+ dev_err(dev, "parsing dt failed (%d)\n", ret);
+ goto pm_runtime_put;
+ }
+
+ ret = sdhci_am654_init(host);
+ if (ret)
+ goto pm_runtime_put;
+
+ return 0;
+
+pm_runtime_put:
+ pm_runtime_put_sync(dev);
+pm_runtime_disable:
+ pm_runtime_disable(dev);
+err_pltfm_free:
+ sdhci_pltfm_free(pdev);
+ return ret;
+}
+
+static int sdhci_am654_remove(struct platform_device *pdev)
+{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ int ret;
+
+ sdhci_remove_host(host, true);
+ ret = pm_runtime_put_sync(&pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ pm_runtime_disable(&pdev->dev);
+ sdhci_pltfm_free(pdev);
+
+ return 0;
+}
+
+static const struct of_device_id sdhci_am654_of_match[] = {
+ { .compatible = "ti,am654-sdhci-5.1" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sdhci_am654_driver = {
+ .driver = {
+ .name = "sdhci-am654",
+ .of_match_table = sdhci_am654_of_match,
+ },
+ .probe = sdhci_am654_probe,
+ .remove = sdhci_am654_remove,
+};
+
+module_platform_driver(sdhci_am654_driver);
+
+MODULE_DESCRIPTION("Driver for SDHCI Controller on TI's AM654 devices");
+MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>");
+MODULE_LICENSE("GPL");
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 2/3] dt-bindings: mmc: sdhci-of-arasan: Add deprecated message for am65
From: Faiz Abbas @ 2018-12-07 8:11 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, devicetree, linux-mmc
Cc: mark.rutland, ulf.hansson, adrian.hunter, kishon, robh+dt,
faiz_abbas, michal.simek
In-Reply-To: <20181207081119.29162-1-faiz_abbas@ti.com>
Commit 26a4f38d1316 ("dt-bindings: mmc: sdhci-of-arasan: Add new
compatible for AM654 MMC PHY") added a new compatible for supporting
controllers on TI's AM65x SOCs. It turns out that the controller is
not compatible with the arasan driver's phy and consumer model as it
requires some phy registers for core sdhci functionality. This calls
for the binding to branch out to a new driver.
Therefore, add a deprecated message for the ti,am654-sdhci-5.1 binding.
Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
Documentation/devicetree/bindings/mmc/arasan,sdhci.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
index e2effe17f05e..1edbb049cccb 100644
--- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
+++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
@@ -16,6 +16,10 @@ Required Properties:
- "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
- "ti,am654-sdhci-5.1", "arasan,sdhci-5.1": TI AM654 MMC PHY
+ Note: This binding has been deprecated and moved to [5].
+
+ [5] Documentation/devicetree/bindings/mmc/sdhci-am654.txt
+
- reg: From mmc bindings: Register location and length.
- clocks: From clock bindings: Handles to clock inputs.
- clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
--
2.19.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox