* [RFC] arm: vdso: Convert sigpage to vdso implementation
From: Steve Capper @ 2014-01-29 14:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52E81BB7.7070201@mentor.com>
On Tue, Jan 28, 2014 at 03:05:59PM -0600, Nathan Lynch wrote:
> Hi Steve,
>
> On 01/28/2014 10:25 AM, Steve Capper wrote:
> > ARM has a special sigpage that is used for signal return trampolines.
> > Its implementation is very similar to a VDSO conceptually in that it
> > occupies a special mapping in user address space.
> >
> > One could actually host the trampoline code in a VDSO instead with the
> > added advantage that one could also host specialised routines there.
> > One such routine could be gettimeofday where on ARM we have architected
> > (and some vendor supplied) timers that can be queried entirely in
> > userspace, obviating the need for an expensive syscall.
> >
> > This patch converts the sigpage implementation to a VDSO. It is mostly
> > a direct port from Will Deacon's arm64 implementation with the ARM
> > signal trampoline plumbed in.
> >
> > Signed-off-by: Steve Capper <steve.capper@linaro.org>
> > ---
> > As can be inferred from this RFC, I am interested ultimately in
> > implementing a syscall-less gettimeofday for ARM. Whilst researching
> > possible vectors page or VDSO implementations, I came across the
> > sigpage mechanism which is very similar to a VDSO.
> >
> > The very simple function, __kernel_vdso_doubler, resolved in a test
> > program automatically on my Arndale board (running Fedora 20) without
> > any additional prodding.
> >
> > IPC stress tests from LTP were executed to test the signal trampoline.
> >
> > I would appreciate any comments on this approach of converting the
> > sigpage to a VDSO. If this looks sane to people, I will work on the
> > gettimeofday logic in a later patch.
>
> As it happens, I've been working on a vDSO implementation of
> gettimeofday/clock_gettime which does not mess with the signal page.
> I'll reply with the patch separately in a moment.
Cheers Nathan,
--
Steve
>
>
^ permalink raw reply
* [RFC PATCH v2 14/14] ARM: sunxi/dt: enable HW ECC on cubietruck board
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 031de97..5828923 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -29,7 +29,7 @@
#size-cells = <1>;
reg = <0>;
allwinner,rb = <0>;
- nand-ecc-mode = "soft_bch";
+ nand-ecc-mode = "hw";
/* nand timings */
tCLS-min = <6>;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 13/14] mtd: nand: add sunxi HW ECC support
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Add HW ECC support for the sunxi NAND Flash Controller.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
drivers/mtd/nand/sunxi_nand.c | 279 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 266 insertions(+), 13 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index d3da810..7e1cefc 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -163,6 +163,11 @@ struct sunxi_nand_chip_sel {
#define DEFAULT_NAME_FORMAT "nand@%d"
#define MAX_NAME_SIZE (sizeof("nand@") + 2)
+struct sunxi_nand_hw_ecc {
+ int mode;
+ struct nand_ecclayout layout;
+};
+
struct sunxi_nand_chip {
struct list_head node;
struct nand_chip nand;
@@ -402,6 +407,126 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
}
+static int sunxi_nfc_hwecc_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_ecclayout *layout = ecc->layout;
+ struct sunxi_nand_hw_ecc *data = ecc->priv;
+ unsigned int max_bitflips = 0;
+ int offset;
+ u32 tmp;
+ int i;
+
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE |
+ NFC_ECC_BLOCK_SIZE);
+ tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT);
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+ for (i = 0; i < mtd->writesize / ecc->size; i++) {
+ if (i)
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
+ chip->read_buf(mtd, NULL, chip->ecc.size);
+ offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+ while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+ ;
+ tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
+ writel(tmp, nfc->regs + NFC_REG_CMD);
+ sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ memcpy_fromio(buf + (i * ecc->size), nfc->regs + NFC_RAM0_BASE,
+ chip->ecc.size);
+
+ if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
+ mtd->ecc_stats.failed++;
+ } else {
+ tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff;
+ mtd->ecc_stats.corrected += tmp;
+ max_bitflips = max_t(unsigned int, max_bitflips, tmp);
+ }
+ }
+
+ if (oob_required) {
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ }
+
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~NFC_ECC_EN;
+
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+ return max_bitflips;
+}
+
+static int sunxi_nfc_hwecc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf,
+ int oob_required)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_ecclayout *layout = ecc->layout;
+ struct sunxi_nand_hw_ecc *data = ecc->priv;
+ int offset;
+ u32 tmp;
+ int i;
+ int j;
+
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE |
+ NFC_ECC_BLOCK_SIZE);
+ tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT);
+
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+ for (i = 0; i < mtd->writesize / ecc->size; i++) {
+ if (i)
+ chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
+
+ chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
+ offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
+ chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
+ while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+ ;
+
+ /* Fill OOB data in */
+ for (j = 0; j < 4; j++) {
+ if (oob_required) {
+ offset = layout->eccpos[i * ecc->size] - 4;
+ writeb(chip->oob_poi[offset + j],
+ nfc->regs + NFC_REG_USER_DATA_BASE + j);
+ } else {
+ writeb(0xff,
+ nfc->regs + NFC_REG_USER_DATA_BASE + j);
+ }
+ }
+
+ tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+ NFC_ACCESS_DIR | (1 << 30);
+ writel(tmp, nfc->regs + NFC_REG_CMD);
+ sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ }
+
+ if (oob_required && chip->ecc.layout->oobfree[0].length > 2) {
+ chip->cmdfunc(mtd, NAND_CMD_RNDIN, mtd->writesize, -1);
+ chip->write_buf(mtd, chip->oob_poi,
+ chip->ecc.layout->oobfree[0].length - 2);
+ }
+
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~(NFC_ECC_EN | NFC_ECC_PIPELINE);
+
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+ return 0;
+}
+
static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
struct device_node *np)
{
@@ -502,6 +627,144 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
return 0;
}
+static int sunxi_nand_chip_hwecc_init(struct device *dev,
+ struct sunxi_nand_chip *chip,
+ struct mtd_info *mtd,
+ struct device_node *np)
+{
+ struct nand_chip *nand = &chip->nand;
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ struct sunxi_nand_hw_ecc *data;
+ struct nand_ecclayout *layout;
+ int nsectors;
+ int i;
+ int j;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ecc->read_page = sunxi_nfc_hwecc_read_page;
+ ecc->write_page = sunxi_nfc_hwecc_write_page;
+
+ if (nand->ecc_strength_ds <= 16) {
+ nand->ecc_strength_ds = 16;
+ data->mode = 0;
+ } else if (nand->ecc_strength_ds <= 24) {
+ nand->ecc_strength_ds = 24;
+ data->mode = 1;
+ } else if (nand->ecc_strength_ds <= 28) {
+ nand->ecc_strength_ds = 28;
+ data->mode = 2;
+ } else if (nand->ecc_strength_ds <= 32) {
+ nand->ecc_strength_ds = 32;
+ data->mode = 3;
+ } else if (nand->ecc_strength_ds <= 40) {
+ nand->ecc_strength_ds = 40;
+ data->mode = 4;
+ } else if (nand->ecc_strength_ds <= 48) {
+ nand->ecc_strength_ds = 48;
+ data->mode = 5;
+ } else if (nand->ecc_strength_ds <= 56) {
+ nand->ecc_strength_ds = 56;
+ data->mode = 6;
+ } else if (nand->ecc_strength_ds <= 60) {
+ nand->ecc_strength_ds = 60;
+ data->mode = 7;
+ } else if (nand->ecc_strength_ds <= 64) {
+ nand->ecc_strength_ds = 64;
+ data->mode = 8;
+ } else {
+ dev_err(dev, "unsupported strength\n");
+ return -ENOTSUPP;
+ }
+
+ /* HW ECC always request ECC bytes for 1024 bytes blocks */
+ ecc->bytes = ((nand->ecc_strength_ds * fls(8 * 1024)) + 7) / 8;
+
+ /* HW ECC always work with even numbers of ECC bytes */
+ if (ecc->bytes % 2)
+ ecc->bytes++;
+ ecc->strength = nand->ecc_strength_ds;
+ ecc->size = nand->ecc_step_ds;
+
+ layout = &data->layout;
+ nsectors = mtd->writesize / ecc->size;
+
+ if (mtd->oobsize < ((ecc->bytes + 4) * nsectors))
+ return -EINVAL;
+
+ layout->eccbytes = (ecc->bytes * nsectors);
+
+ /*
+ * The first 2 bytes are used for BB markers.
+ * We merge the 4 user available bytes from HW ECC with this
+ * first section, hence why the + 2 operation (- 2 + 4).
+ */
+ layout->oobfree[0].length = mtd->oobsize + 2 -
+ ((ecc->bytes + 4) * nsectors);
+ layout->oobfree[0].offset = 2;
+ for (i = 0; i < nsectors; i++) {
+ /*
+ * The first 4 ECC block bytes are already counted in the first
+ * obbfree entry.
+ */
+ if (i) {
+ layout->oobfree[i].offset =
+ layout->oobfree[i - 1].offset +
+ layout->oobfree[i - 1].length +
+ ecc->bytes;
+ layout->oobfree[i].length = 4;
+ }
+
+ for (j = 0; j < ecc->bytes; j++)
+ layout->eccpos[(ecc->bytes * i) + j] =
+ layout->oobfree[i].offset +
+ layout->oobfree[i].length + j;
+ }
+
+ ecc->layout = layout;
+ ecc->priv = data;
+
+ return 0;
+}
+
+static int sunxi_nand_chip_ecc_init(struct device *dev,
+ struct sunxi_nand_chip *chip,
+ struct mtd_info *mtd,
+ struct device_node *np)
+{
+ struct nand_chip *nand = &chip->nand;
+ u32 strength;
+ u32 blk_size;
+ int ret;
+
+ nand->ecc.mode = of_get_nand_ecc_mode(np);
+
+ if (!of_get_nand_ecc_level(np, &strength, &blk_size)) {
+ nand->ecc_step_ds = blk_size;
+ nand->ecc_strength_ds = strength;
+ }
+
+ switch (nand->ecc.mode) {
+ case NAND_ECC_SOFT_BCH:
+ nand->ecc.size = nand->ecc_step_ds;
+ nand->ecc.bytes = ((nand->ecc_strength_ds *
+ fls(8 * nand->ecc_step_ds)) + 7) / 8;
+ break;
+ case NAND_ECC_HW:
+ ret = sunxi_nand_chip_hwecc_init(dev, chip, mtd, np);
+ if (ret)
+ return ret;
+ break;
+ case NAND_ECC_NONE:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
@@ -509,8 +772,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct mtd_part_parser_data ppdata;
struct mtd_info *mtd;
struct nand_chip *nand;
- u32 strength;
- u32 blk_size;
int nsels;
int ret;
int i;
@@ -576,7 +837,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->write_buf = sunxi_nfc_write_buf;
nand->read_byte = sunxi_nfc_read_byte;
- nand->ecc.mode = of_get_nand_ecc_mode(np);
if (of_get_nand_on_flash_bbt(np))
nand->bbt_options |= NAND_BBT_USE_FLASH;
@@ -588,16 +848,9 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
if (ret)
return ret;
- if (nand->ecc.mode == NAND_ECC_SOFT_BCH) {
- if (!of_get_nand_ecc_level(np, &strength, &blk_size)) {
- nand->ecc_step_ds = blk_size;
- nand->ecc_strength_ds = strength;
- }
-
- nand->ecc.size = nand->ecc_step_ds;
- nand->ecc.bytes = (((nand->ecc_strength_ds *
- fls(8 * nand->ecc_step_ds)) + 7) / 8);
- }
+ ret = sunxi_nand_chip_ecc_init(dev, chip, mtd, np);
+ if (ret)
+ return ret;
ret = nand_scan_tail(mtd);
if (ret)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 12/14] ARM: sunxi/dt: enable NAND on cubietruck board
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Enable the NFC and describe the NAND flash connected to this controller.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 31 ++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 8a1009d..031de97 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -19,6 +19,37 @@
compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
soc at 01c00000 {
+ nfc: nand at 01c03000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+ status = "okay";
+
+ nand at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>;
+ allwinner,rb = <0>;
+ nand-ecc-mode = "soft_bch";
+
+ /* nand timings */
+ tCLS-min = <6>;
+ tCLH-min = <3>;
+ tCS-min = <20>;
+ tCH-min = <5>;
+ tWP-min = <8>;
+ tWH-min = <6>;
+ tALS-min = <6>;
+ tDS-min = <6>;
+ tDH-min = <2>;
+ tRR-min = <20>;
+ tALH-min = <3>;
+ tRP-min = <8>;
+ tREH-min = <6>;
+ tRC-min = <16>;
+ tWC-min = <16>;
+ };
+ };
+
pinctrl at 01c20800 {
led_pins_cubietruck: led_pins at 0 {
allwinner,pins = "PH7", "PH11", "PH20", "PH21";
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 11/14] ARM: dt/sunxi: add NFC pinctrl pin definitions
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Define the NAND pinctrl configs.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 3b47253..0f6e002 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -389,6 +389,30 @@
allwinner,drive = <0>;
allwinner,pull = <0>;
};
+
+ nand_pins_a: nand_base0 at 0 {
+ allwinner,pins = "PC0", "PC1", "PC2",
+ "PC5", "PC8", "PC9", "PC10",
+ "PC11", "PC12", "PC13", "PC14",
+ "PC15", "PC16";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs0_pins_a: nand_cs at 0 {
+ allwinner,pins = "PC4";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb0_pins_a: nand_rb at 0 {
+ allwinner,pins = "PC6";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
timer at 01c20c00 {
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 10/14] ARM: dt/sunxi: add NFC node to Allwinner A20 SoC
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Add NAND Flash controller node definition to the A20 SoC.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 8e4cdcc..3b47253 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -299,6 +299,17 @@
#size-cells = <1>;
ranges;
+ nfc: nand at 01c03000 {
+ compatible = "allwinner,sun4i-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <0 37 1>;
+ clocks = <&ahb_gates 13>, <&nand_clk>;
+ clock-names = "ahb_clk", "sclk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
emac: ethernet at 01c0b000 {
compatible = "allwinner,sun4i-emac";
reg = <0x01c0b000 0x1000>;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 09/14] mtd: nand: add sunxi NFC dt bindings doc
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Add the sunxi NAND Flash Controller dt bindings documentation.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
.../devicetree/bindings/mtd/sunxi-nand.txt | 46 ++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt
diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
new file mode 100644
index 0000000..b0e55a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
@@ -0,0 +1,46 @@
+Allwinner NAND Flash Controller (NFC)
+
+Required properties:
+- compatible : "allwinner,sun4i-nand".
+- reg : shall contain registers location and length for data and reg.
+- interrupts : shall define the nand controller interrupt.
+- #address-cells: shall be set to 1. Encode the nand CS.
+- #size-cells : shall be set to 0.
+- clocks : shall reference nand controller clocks.
+- clock-names : nand controller internal clock names. Shall contain :
+ * "ahb_clk" : AHB gating clock
+ * "sclk" : nand controller clock
+
+Optional children nodes:
+Children nodes represent the available nand chips.
+
+Optional properties:
+- onfi,nand-timing-mode : mandatory if the chip does not support the ONFI
+ standard.
+- allwinner,rb : shall contain the native Ready/Busy ids.
+ or
+- rb-gpios : shall contain the gpios used as R/B pins.
+
+see Documentation/devicetree/mtd/nand.txt for generic bindings.
+
+
+Examples:
+nfc: nand at 01c03000 {
+ compatible = "allwinner,sun4i-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <0 37 1>;
+ clocks = <&ahb_gates 13>, <&nand_clk>;
+ clock-names = "ahb_clk", "sclk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+ status = "okay";
+
+ nand at 0 {
+ reg = <0>;
+ allwinner,rb = <0>;
+ nand-ecc-mode = "soft_bch";
+ onfi,nand-timing-mode = <4>;
+ };
+};
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 08/14] mtd: nand: add sunxi NAND flash controller support
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Add support for the sunxi NAND Flash Controller (NFC).
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
drivers/mtd/nand/Kconfig | 6 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/sunxi_nand.c | 744 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 751 insertions(+)
create mode 100644 drivers/mtd/nand/sunxi_nand.c
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 93ae6a6..784dd42 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -510,4 +510,10 @@ config MTD_NAND_XWAY
Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
to the External Bus Unit (EBU).
+config MTD_NAND_SUNXI
+ tristate "Support for NAND on Allwinner SoCs"
+ depends on ARCH_SUNXI
+ help
+ Enables support for NAND Flash chips on Allwinner SoCs.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index bbea7a6..e3b4a34 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -49,5 +49,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
+obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
new file mode 100644
index 0000000..d3da810
--- /dev/null
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
+ *
+ * Derived from:
+ * https://github.com/yuq/sunxi-nfc-mtd
+ * Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
+ *
+ * https://github.com/hno/Allwinner-Info
+ * Copyright (C) 2013 Henrik Nordstr?m <Henrik Nordstr?m>
+ *
+ * Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
+ * Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_mtd.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define NFC_REG_CTL 0x0000
+#define NFC_REG_ST 0x0004
+#define NFC_REG_INT 0x0008
+#define NFC_REG_TIMING_CTL 0x000C
+#define NFC_REG_TIMING_CFG 0x0010
+#define NFC_REG_ADDR_LOW 0x0014
+#define NFC_REG_ADDR_HIGH 0x0018
+#define NFC_REG_SECTOR_NUM 0x001C
+#define NFC_REG_CNT 0x0020
+#define NFC_REG_CMD 0x0024
+#define NFC_REG_RCMD_SET 0x0028
+#define NFC_REG_WCMD_SET 0x002C
+#define NFC_REG_IO_DATA 0x0030
+#define NFC_REG_ECC_CTL 0x0034
+#define NFC_REG_ECC_ST 0x0038
+#define NFC_REG_DEBUG 0x003C
+#define NFC_REG_ECC_CNT0 0x0040
+#define NFC_REG_ECC_CNT1 0x0044
+#define NFC_REG_ECC_CNT2 0x0048
+#define NFC_REG_ECC_CNT3 0x004c
+#define NFC_REG_USER_DATA_BASE 0x0050
+#define NFC_REG_SPARE_AREA 0x00A0
+#define NFC_RAM0_BASE 0x0400
+#define NFC_RAM1_BASE 0x0800
+
+/*define bit use in NFC_CTL*/
+#define NFC_EN (1 << 0)
+#define NFC_RESET (1 << 1)
+#define NFC_BUS_WIDYH (1 << 2)
+#define NFC_RB_SEL (1 << 3)
+#define NFC_CE_SEL (7 << 24)
+#define NFC_CE_CTL (1 << 6)
+#define NFC_CE_CTL1 (1 << 7)
+#define NFC_PAGE_SIZE (0xf << 8)
+#define NFC_SAM (1 << 12)
+#define NFC_RAM_METHOD (1 << 14)
+#define NFC_DEBUG_CTL (1 << 31)
+
+/*define bit use in NFC_ST*/
+#define NFC_RB_B2R (1 << 0)
+#define NFC_CMD_INT_FLAG (1 << 1)
+#define NFC_DMA_INT_FLAG (1 << 2)
+#define NFC_CMD_FIFO_STATUS (1 << 3)
+#define NFC_STA (1 << 4)
+#define NFC_NATCH_INT_FLAG (1 << 5)
+#define NFC_RB_STATE0 (1 << 8)
+#define NFC_RB_STATE1 (1 << 9)
+#define NFC_RB_STATE2 (1 << 10)
+#define NFC_RB_STATE3 (1 << 11)
+
+/*define bit use in NFC_INT*/
+#define NFC_B2R_INT_ENABLE (1 << 0)
+#define NFC_CMD_INT_ENABLE (1 << 1)
+#define NFC_DMA_INT_ENABLE (1 << 2)
+#define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \
+ NFC_CMD_INT_ENABLE | \
+ NFC_DMA_INT_ENABLE)
+
+
+/*define bit use in NFC_CMD*/
+#define NFC_CMD_LOW_BYTE (0xff << 0)
+#define NFC_CMD_HIGH_BYTE (0xff << 8)
+#define NFC_ADR_NUM (0x7 << 16)
+#define NFC_SEND_ADR (1 << 19)
+#define NFC_ACCESS_DIR (1 << 20)
+#define NFC_DATA_TRANS (1 << 21)
+#define NFC_SEND_CMD1 (1 << 22)
+#define NFC_WAIT_FLAG (1 << 23)
+#define NFC_SEND_CMD2 (1 << 24)
+#define NFC_SEQ (1 << 25)
+#define NFC_DATA_SWAP_METHOD (1 << 26)
+#define NFC_ROW_AUTO_INC (1 << 27)
+#define NFC_SEND_CMD3 (1 << 28)
+#define NFC_SEND_CMD4 (1 << 29)
+#define NFC_CMD_TYPE (3 << 30)
+
+/* define bit use in NFC_RCMD_SET*/
+#define NFC_READ_CMD (0xff << 0)
+#define NFC_RANDOM_READ_CMD0 (0xff << 8)
+#define NFC_RANDOM_READ_CMD1 (0xff << 16)
+
+/*define bit use in NFC_WCMD_SET*/
+#define NFC_PROGRAM_CMD (0xff << 0)
+#define NFC_RANDOM_WRITE_CMD (0xff << 8)
+#define NFC_READ_CMD0 (0xff << 16)
+#define NFC_READ_CMD1 (0xff << 24)
+
+/*define bit use in NFC_ECC_CTL*/
+#define NFC_ECC_EN (1 << 0)
+#define NFC_ECC_PIPELINE (1 << 3)
+#define NFC_ECC_EXCEPTION (1 << 4)
+#define NFC_ECC_BLOCK_SIZE (1 << 5)
+#define NFC_RANDOM_EN (1 << 9)
+#define NFC_RANDOM_DIRECTION (1 << 10)
+#define NFC_ECC_MODE_SHIFT 12
+#define NFC_ECC_MODE (0xf << NFC_ECC_MODE_SHIFT)
+#define NFC_RANDOM_SEED (0x7fff << 16)
+
+
+
+enum sunxi_nand_rb_type {
+ RB_NONE,
+ RB_NATIVE,
+ RB_GPIO,
+};
+
+struct sunxi_nand_rb {
+ enum sunxi_nand_rb_type type;
+ union {
+ int gpio;
+ int nativeid;
+ } info;
+};
+
+struct sunxi_nand_chip_sel {
+ u8 cs;
+ struct sunxi_nand_rb rb;
+};
+
+#define DEFAULT_NAME_FORMAT "nand@%d"
+#define MAX_NAME_SIZE (sizeof("nand@") + 2)
+
+struct sunxi_nand_chip {
+ struct list_head node;
+ struct nand_chip nand;
+ struct mtd_info mtd;
+ char default_name[MAX_NAME_SIZE];
+ unsigned long clk_rate;
+ int selected;
+ int nsels;
+ struct sunxi_nand_chip_sel sels[0];
+};
+
+static inline struct sunxi_nand_chip *to_sunxi_nand(struct mtd_info *mtd)
+{
+ return container_of(mtd, struct sunxi_nand_chip, mtd);
+}
+
+struct sunxi_nfc {
+ struct nand_hw_control controller;
+ void __iomem *regs;
+ int irq;
+ struct clk *ahb_clk;
+ struct clk *sclk;
+ unsigned long assigned_cs;
+ unsigned long clk_rate;
+ struct list_head chips;
+ struct completion complete;
+};
+
+static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
+{
+ return container_of(ctrl, struct sunxi_nfc, controller);
+}
+
+static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
+{
+ struct sunxi_nfc *nfc = dev_id;
+ u32 st = readl(nfc->regs + NFC_REG_ST);
+ u32 ien = readl(nfc->regs + NFC_REG_INT);
+
+ if (!(ien & st))
+ return IRQ_NONE;
+
+ if ((ien & st) == ien)
+ complete(&nfc->complete);
+
+ writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
+ writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
+
+ return IRQ_HANDLED;
+}
+
+static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags,
+ unsigned int timeout_ms)
+{
+ init_completion(&nfc->complete);
+
+ writel(flags, nfc->regs + NFC_REG_INT);
+ if (!timeout_ms)
+ wait_for_completion(&nfc->complete);
+ else if (!wait_for_completion_timeout(&nfc->complete,
+ msecs_to_jiffies(timeout_ms)))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ struct sunxi_nand_rb *rb;
+ unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20);
+ int ret;
+
+ if (sunxi_nand->selected < 0)
+ return 0;
+
+ rb = &sunxi_nand->sels[sunxi_nand->selected].rb;
+
+ switch (rb->type) {
+ case RB_NATIVE:
+ ret = !!(readl(nfc->regs + NFC_REG_ST) &
+ (NFC_RB_STATE0 << rb->info.nativeid));
+ if (ret)
+ break;
+
+ sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo);
+ ret = !!(readl(nfc->regs + NFC_REG_ST) &
+ (NFC_RB_STATE0 << rb->info.nativeid));
+ break;
+ case RB_GPIO:
+ ret = gpio_get_value(rb->info.gpio);
+ break;
+ case RB_NONE:
+ default:
+ ret = 0;
+ dev_err(&mtd->dev, "cannot check R/B NAND status!");
+ break;
+ }
+
+ return ret;
+}
+
+static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+ struct nand_chip *nand = &sunxi_nand->nand;
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ struct sunxi_nand_chip_sel *sel;
+ u32 ctl;
+
+ if (chip > 0 && chip >= sunxi_nand->nsels)
+ return;
+
+ if (chip == sunxi_nand->selected)
+ return;
+
+ ctl = readl(nfc->regs + NFC_REG_CTL) &
+ ~(NFC_CE_SEL | NFC_RB_SEL | NFC_EN);
+
+ if (chip >= 0) {
+ sel = &sunxi_nand->sels[chip];
+
+ ctl |= (sel->cs << 24) | NFC_EN |
+ (((nand->page_shift - 10) & 0xf) << 8);
+ if (sel->rb.type == RB_NONE) {
+ nand->dev_ready = NULL;
+ } else {
+ nand->dev_ready = sunxi_nfc_dev_ready;
+ if (sel->rb.type == RB_NATIVE)
+ ctl |= (sel->rb.info.nativeid << 3);
+ }
+
+ writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
+
+ if (nfc->clk_rate != sunxi_nand->clk_rate) {
+ clk_set_rate(nfc->sclk, sunxi_nand->clk_rate);
+ nfc->clk_rate = sunxi_nand->clk_rate;
+ }
+ }
+
+ writel(ctl, nfc->regs + NFC_REG_CTL);
+
+ sunxi_nand->selected = chip;
+}
+
+static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ int cnt;
+ int offs = 0;
+ u32 tmp;
+
+ while (len > offs) {
+ cnt = len - offs;
+ if (cnt > 1024)
+ cnt = 1024;
+
+ while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+ ;
+ writel(cnt, nfc->regs + NFC_REG_CNT);
+ tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
+ writel(tmp, nfc->regs + NFC_REG_CMD);
+ sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ if (buf)
+ memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
+ cnt);
+ offs += cnt;
+ }
+}
+
+static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+ int len)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ int cnt;
+ int offs = 0;
+ u32 tmp;
+
+ while (len > offs) {
+ cnt = len - offs;
+ if (cnt > 1024)
+ cnt = 1024;
+
+ while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+ ;
+ writel(cnt, nfc->regs + NFC_REG_CNT);
+ memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
+ tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+ NFC_ACCESS_DIR;
+ writel(tmp, nfc->regs + NFC_REG_CMD);
+ sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ offs += cnt;
+ }
+}
+
+static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+{
+ uint8_t ret;
+
+ sunxi_nfc_read_buf(mtd, &ret, 1);
+
+ return ret;
+}
+
+static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+ unsigned int ctrl)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ u32 tmp;
+
+ while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+ ;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ tmp = readl(nfc->regs + NFC_REG_CTL);
+ if (ctrl & NAND_NCE)
+ tmp |= NFC_CE_CTL;
+ else
+ tmp &= ~NFC_CE_CTL;
+ writel(tmp, nfc->regs + NFC_REG_CTL);
+ }
+
+ if (dat == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE) {
+ writel(NFC_SEND_CMD1 | dat, nfc->regs + NFC_REG_CMD);
+ } else {
+ writel(dat, nfc->regs + NFC_REG_ADDR_LOW);
+ writel(NFC_SEND_ADR, nfc->regs + NFC_REG_CMD);
+ }
+
+ sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+}
+
+static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
+ struct device_node *np)
+{
+ const struct nand_sdr_timings *timings;
+ u32 min_clk_period = 0;
+ int ret;
+
+ ret = onfi_get_async_timing_mode(&chip->nand);
+ if (ret == ONFI_TIMING_MODE_UNKNOWN) {
+ ret = of_get_nand_onfi_timing_mode(np);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = fls(ret);
+ if (!ret)
+ return -EINVAL;
+
+ timings = onfi_async_timing_mode_to_sdr_timings(ret - 1);
+ if (IS_ERR(timings))
+ return PTR_ERR(timings);
+
+ /* NFC timings defined in Allwinner Datasheets */
+
+ /* T1 <=> tCLS */
+ if (timings->tCLS_min > min_clk_period)
+ min_clk_period = timings->tCLS_min;
+
+ /* T2 <=> tCLH */
+ if (timings->tCLH_min > min_clk_period)
+ min_clk_period = timings->tCLH_min;
+
+ /* T3 <=> tCS */
+ if (timings->tCS_min > min_clk_period)
+ min_clk_period = timings->tCS_min;
+
+ /* T4 <=> tCH */
+ if (timings->tCH_min > min_clk_period)
+ min_clk_period = timings->tCH_min;
+
+ /* T5 <=> tWP */
+ if (timings->tWP_min > min_clk_period)
+ min_clk_period = timings->tWP_min;
+
+ /* T6 <=> tWH */
+ if (timings->tWH_min > min_clk_period)
+ min_clk_period = timings->tWH_min;
+
+ /* T7 <=> tALS */
+ if (timings->tALS_min > min_clk_period)
+ min_clk_period = timings->tALS_min;
+
+ /* T8 <=> tDS */
+ if (timings->tDS_min > min_clk_period)
+ min_clk_period = timings->tDS_min;
+
+ /* T9 <=> tDH */
+ if (timings->tDH_min > min_clk_period)
+ min_clk_period = timings->tDH_min;
+
+ /* T10 <=> tRR */
+ if (timings->tRR_min > (min_clk_period * 3))
+ min_clk_period = (timings->tRR_min + 2) / 3;
+
+ /* T11 <=> tALH */
+ if (timings->tALH_min > min_clk_period)
+ min_clk_period = timings->tALH_min;
+
+ /* T12 <=> tRP */
+ if (timings->tRP_min > min_clk_period)
+ min_clk_period = timings->tRP_min;
+
+ /* T13 <=> tREH */
+ if (timings->tREH_min > min_clk_period)
+ min_clk_period = timings->tREH_min;
+
+ /* T14 <=> tRC */
+ if (timings->tRC_min > (min_clk_period * 2))
+ min_clk_period = (timings->tRC_min + 1) / 2;
+
+ /* T15 <=> tWC */
+ if (timings->tWC_min > (min_clk_period * 2))
+ min_clk_period = (timings->tWC_min + 1) / 2;
+
+
+ /* min_clk_period = (NAND-clk-period * 2) */
+ if (!min_clk_period) {
+ chip->clk_rate = 20000000;
+ } else {
+ min_clk_period /= 1000;
+ if (!min_clk_period)
+ min_clk_period = 1;
+ chip->clk_rate = (2 * 1000000000) / min_clk_period;
+ }
+
+ /* TODO: configure T16-T19 */
+
+ return 0;
+}
+
+static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
+ struct device_node *np)
+{
+ struct sunxi_nand_chip *chip;
+ struct mtd_part_parser_data ppdata;
+ struct mtd_info *mtd;
+ struct nand_chip *nand;
+ u32 strength;
+ u32 blk_size;
+ int nsels;
+ int ret;
+ int i;
+ u32 tmp;
+
+ if (!of_get_property(np, "reg", &nsels))
+ return -EINVAL;
+
+ nsels /= sizeof(u32);
+ if (!nsels)
+ return -EINVAL;
+
+ chip = devm_kzalloc(dev,
+ sizeof(*chip) +
+ (nsels * sizeof(struct sunxi_nand_chip_sel)),
+ GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->nsels = nsels;
+ chip->selected = -1;
+
+ for (i = 0; i < nsels; i++) {
+ ret = of_property_read_u32_index(np, "reg", i, &tmp);
+ if (ret)
+ return ret;
+
+ if (tmp > 7)
+ return -EINVAL;
+
+ if (test_and_set_bit(tmp, &nfc->assigned_cs))
+ return -EINVAL;
+
+ chip->sels[i].cs = tmp;
+
+ if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
+ tmp < 2) {
+ chip->sels[i].rb.type = RB_NATIVE;
+ chip->sels[i].rb.info.nativeid = tmp;
+ } else {
+ ret = of_get_named_gpio(np, "rb-gpios", i);
+ if (ret >= 0) {
+ chip->sels[i].rb.type = RB_GPIO;
+ chip->sels[i].rb.info.gpio = tmp;
+ ret = devm_gpio_request(dev, tmp, "nand-rb");
+ if (ret)
+ return ret;
+ } else {
+ chip->sels[i].rb.type = RB_NONE;
+ }
+ }
+ }
+
+ ret = sunxi_nand_chip_init_timings(chip, np);
+ if (ret)
+ return ret;
+
+ nand = &chip->nand;
+ nand->controller = &nfc->controller;
+ nand->select_chip = sunxi_nfc_select_chip;
+ nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
+ nand->read_buf = sunxi_nfc_read_buf;
+ nand->write_buf = sunxi_nfc_write_buf;
+ nand->read_byte = sunxi_nfc_read_byte;
+
+ nand->ecc.mode = of_get_nand_ecc_mode(np);
+ if (of_get_nand_on_flash_bbt(np))
+ nand->bbt_options |= NAND_BBT_USE_FLASH;
+
+ mtd = &chip->mtd;
+ mtd->priv = nand;
+ mtd->owner = THIS_MODULE;
+
+ ret = nand_scan_ident(mtd, nsels, NULL);
+ if (ret)
+ return ret;
+
+ if (nand->ecc.mode == NAND_ECC_SOFT_BCH) {
+ if (!of_get_nand_ecc_level(np, &strength, &blk_size)) {
+ nand->ecc_step_ds = blk_size;
+ nand->ecc_strength_ds = strength;
+ }
+
+ nand->ecc.size = nand->ecc_step_ds;
+ nand->ecc.bytes = (((nand->ecc_strength_ds *
+ fls(8 * nand->ecc_step_ds)) + 7) / 8);
+ }
+
+ ret = nand_scan_tail(mtd);
+ if (ret)
+ return ret;
+
+ if (of_property_read_string(np, "nand-name", &mtd->name)) {
+ snprintf(chip->default_name, MAX_NAME_SIZE,
+ DEFAULT_NAME_FORMAT, chip->sels[i].cs);
+ mtd->name = chip->default_name;
+ }
+
+ ppdata.of_node = np;
+ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ if (!ret)
+ return ret;
+
+ list_add_tail(&chip->node, &nfc->chips);
+
+ return 0;
+}
+
+static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *nand_np;
+ int nchips = of_get_child_count(np);
+ int ret;
+
+ if (nchips > 8)
+ return -EINVAL;
+
+ for_each_child_of_node(np, nand_np) {
+ ret = sunxi_nand_chip_init(dev, nfc, nand_np);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sunxi_nfc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *r;
+ struct sunxi_nfc *nfc;
+ int ret;
+
+ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+ if (!nfc) {
+ dev_err(dev, "failed to allocate NFC struct\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&nfc->controller.lock);
+ init_waitqueue_head(&nfc->controller.wq);
+ INIT_LIST_HEAD(&nfc->chips);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ nfc->regs = devm_ioremap_resource(dev, r);
+ if (IS_ERR(nfc->regs)) {
+ dev_err(dev, "failed to remap iomem\n");
+ return PTR_ERR(nfc->regs);
+ }
+
+ nfc->irq = platform_get_irq(pdev, 0);
+ if (nfc->irq < 0) {
+ dev_err(dev, "failed to retrieve irq\n");
+ return nfc->irq;
+ }
+
+ nfc->ahb_clk = devm_clk_get(dev, "ahb_clk");
+ if (IS_ERR(nfc->ahb_clk)) {
+ dev_err(dev, "failed to retrieve ahb_clk\n");
+ return PTR_ERR(nfc->ahb_clk);
+ }
+
+ ret = clk_prepare_enable(nfc->ahb_clk);
+ if (ret)
+ return ret;
+
+ nfc->sclk = devm_clk_get(dev, "sclk");
+ if (IS_ERR(nfc->sclk)) {
+ dev_err(dev, "failed to retrieve nand_clk\n");
+ ret = PTR_ERR(nfc->sclk);
+ goto out_ahb_clk_unprepare;
+ }
+
+ ret = clk_prepare_enable(nfc->sclk);
+ if (ret)
+ goto out_ahb_clk_unprepare;
+
+ /* Reset NFC */
+ writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RESET,
+ nfc->regs + NFC_REG_CTL);
+ while (readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)
+ ;
+
+ writel(0, nfc->regs + NFC_REG_INT);
+ ret = devm_request_irq(dev, nfc->irq, sunxi_nfc_interrupt,
+ 0, "sunxi-nand", nfc);
+ if (ret)
+ goto out_sclk_unprepare;
+
+ platform_set_drvdata(pdev, nfc);
+
+ writel(0x100, nfc->regs + NFC_REG_TIMING_CTL);
+ writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG);
+
+ ret = sunxi_nand_chips_init(dev, nfc);
+ if (ret) {
+ dev_err(dev, "failed to init nand chips\n");
+ goto out_sclk_unprepare;
+ }
+
+ return 0;
+
+out_sclk_unprepare:
+ clk_disable_unprepare(nfc->sclk);
+out_ahb_clk_unprepare:
+ clk_disable_unprepare(nfc->ahb_clk);
+
+ return ret;
+}
+
+static const struct of_device_id sunxi_nfc_ids[] = {
+ { .compatible = "allwinner,sun4i-nand" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
+
+static struct platform_driver sunxi_nfc_driver = {
+ .driver = {
+ .name = "sunxi_nand",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(sunxi_nfc_ids),
+ },
+ .probe = sunxi_nfc_probe,
+};
+module_platform_driver(sunxi_nfc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Boris BREZILLON");
+MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
+MODULE_ALIAS("platform:sunxi_nfc");
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 07/14] of: mtd: add documentation for the ONFI NAND timing mode property
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Add documentation for the ONFI NAND timing mode property.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
Documentation/devicetree/bindings/mtd/nand.txt | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index 0c962296..75e46f3 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -8,3 +8,8 @@
E.g. : nand-ecc-level = <4 512>; /* 4 bits / 512 bytes */
- nand-bus-width : 8 or 16 bus width if not present 8
- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+- onfi,nand-timing-mode: an integer encoding the ONFI timing mode of the NAND
+ chip. This is only used when the chip does not support the ONFI standard.
+ Choose the closest mode fulfilling the NAND chip timings.
+ For a full description of the different timing modes see this document:
+ www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf?
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 06/14] of: mtd: add NAND timing mode retrieval support
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Add a function to retrieve NAND timing mode (ONFI timing mode) from a given
DT node.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
drivers/of/of_mtd.c | 19 +++++++++++++++++++
include/linux/of_mtd.h | 8 ++++++++
2 files changed, 27 insertions(+)
diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
index e8ced61..63155d4 100644
--- a/drivers/of/of_mtd.c
+++ b/drivers/of/of_mtd.c
@@ -108,3 +108,22 @@ bool of_get_nand_on_flash_bbt(struct device_node *np)
return of_property_read_bool(np, "nand-on-flash-bbt");
}
EXPORT_SYMBOL_GPL(of_get_nand_on_flash_bbt);
+
+/**
+ * of_get_nand_timings - Get nand timings for the given device_node
+ * @np: Pointer to the given device_node
+ *
+ * return 0 on success errno other wise
+ */
+int of_get_nand_onfi_timing_mode(struct device_node *np)
+{
+ int err;
+ u32 mode;
+
+ err = of_property_read_u32(np, "onfi,nand-timing-mode", &mode);
+ if (err)
+ return err;
+
+ return mode;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_onfi_timing_mode);
diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h
index 3bd8c3b..eb9fda6 100644
--- a/include/linux/of_mtd.h
+++ b/include/linux/of_mtd.h
@@ -9,6 +9,8 @@
#ifndef __LINUX_OF_MTD_H
#define __LINUX_OF_NET_H
+#include <linux/mtd/nand.h>
+
#ifdef CONFIG_OF_MTD
#include <linux/of.h>
@@ -16,6 +18,7 @@ int of_get_nand_ecc_mode(struct device_node *np);
int of_get_nand_ecc_level(struct device_node *np, u32 *strengh, u32 *blk_size);
int of_get_nand_bus_width(struct device_node *np);
bool of_get_nand_on_flash_bbt(struct device_node *np);
+int of_get_nand_onfi_timing_mode(struct device_node *np);
#else /* CONFIG_OF_MTD */
@@ -40,6 +43,11 @@ static inline bool of_get_nand_on_flash_bbt(struct device_node *np)
return false;
}
+static inline int of_get_nand_onfi_timing_mode(struct device_node *np)
+{
+ return -ENOSYS;
+}
+
#endif /* CONFIG_OF_MTD */
#endif /* __LINUX_OF_MTD_H */
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 05/14] mtd: nand: add ONFI timing mode to nand_timings converter
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Add a converter to retrieve NAND timings from an ONFI NAND timing mode.
This only support SDR NAND timings for now.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
drivers/mtd/nand/Makefile | 2 +-
drivers/mtd/nand/nand_timings.c | 248 +++++++++++++++++++++++++++++++++++++++
include/linux/mtd/nand.h | 4 +
3 files changed, 253 insertions(+), 1 deletion(-)
create mode 100644 drivers/mtd/nand/nand_timings.c
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 542b568..bbea7a6 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -2,7 +2,7 @@
# linux/drivers/nand/Makefile
#
-obj-$(CONFIG_MTD_NAND) += nand.o
+obj-$(CONFIG_MTD_NAND) += nand.o nand_timings.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
new file mode 100644
index 0000000..f66fe95
--- /dev/null
+++ b/drivers/mtd/nand/nand_timings.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2014 Boris BREZILLON <b.brezillon.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/mtd/nand.h>
+
+static const struct nand_sdr_timings onfi_sdr_timings[] = {
+ /* Mode 0 */
+ {
+ .tADL_min = 200000,
+ .tALH_min = 20000,
+ .tALS_min = 50000,
+ .tAR_min = 25000,
+ .tCEA_max = 100000,
+ .tCEH_min = 20000,
+ .tCH_min = 20000,
+ .tCHZ_max = 100000,
+ .tCLH_min = 20000,
+ .tCLR_min = 20000,
+ .tCLS_min = 50000,
+ .tCOH_min = 0,
+ .tCS_min = 70000,
+ .tDH_min = 20000,
+ .tDS_min = 40000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 10000,
+ .tITC_max = 1000000,
+ .tRC_min = 100000,
+ .tREA_max = 40000,
+ .tREH_min = 30000,
+ .tRHOH_min = 0,
+ .tRHW_min = 200000,
+ .tRHZ_max = 200000,
+ .tRLOH_min = 0,
+ .tRP_min = 50000,
+ .tRST_max = 250000000000,
+ .tWB_max = 200000,
+ .tRR_min = 40000,
+ .tWC_min = 100000,
+ .tWH_min = 30000,
+ .tWHR_min = 120000,
+ .tWP_min = 50000,
+ .tWW_min = 100000,
+ },
+ /* Mode 1 */
+ {
+ .tADL_min = 100000,
+ .tALH_min = 10000,
+ .tALS_min = 25000,
+ .tAR_min = 10000,
+ .tCEA_max = 45000,
+ .tCEH_min = 20000,
+ .tCH_min = 10000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 10000,
+ .tCLR_min = 10000,
+ .tCLS_min = 25000,
+ .tCOH_min = 15000,
+ .tCS_min = 35000,
+ .tDH_min = 10000,
+ .tDS_min = 20000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 50000,
+ .tREA_max = 30000,
+ .tREH_min = 15000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRP_min = 25000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 45000,
+ .tWH_min = 15000,
+ .tWHR_min = 80000,
+ .tWP_min = 25000,
+ .tWW_min = 100000,
+ },
+ /* Mode 2 */
+ {
+ .tADL_min = 100000,
+ .tALH_min = 10000,
+ .tALS_min = 15000,
+ .tAR_min = 10000,
+ .tCEA_max = 30000,
+ .tCEH_min = 20000,
+ .tCH_min = 10000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 10000,
+ .tCLR_min = 10000,
+ .tCLS_min = 15000,
+ .tCOH_min = 15000,
+ .tCS_min = 25000,
+ .tDH_min = 5000,
+ .tDS_min = 15000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 35000,
+ .tREA_max = 25000,
+ .tREH_min = 15000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tRP_min = 17000,
+ .tWC_min = 35000,
+ .tWH_min = 15000,
+ .tWHR_min = 80000,
+ .tWP_min = 17000,
+ .tWW_min = 100000,
+ },
+ /* Mode 3 */
+ {
+ .tADL_min = 100000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 25000,
+ .tDH_min = 5000,
+ .tDS_min = 10000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 30000,
+ .tREA_max = 20000,
+ .tREH_min = 10000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRP_min = 15000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 30000,
+ .tWH_min = 10000,
+ .tWHR_min = 80000,
+ .tWP_min = 15000,
+ .tWW_min = 100000,
+ },
+ /* Mode 4 */
+ {
+ .tADL_min = 70000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 30000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 20000,
+ .tDH_min = 5000,
+ .tDS_min = 10000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 25000,
+ .tREA_max = 20000,
+ .tREH_min = 10000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 5000,
+ .tRP_min = 12000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 25000,
+ .tWH_min = 10000,
+ .tWHR_min = 80000,
+ .tWP_min = 12000,
+ .tWW_min = 100000,
+ },
+ /* Mode 5 */
+ {
+ .tADL_min = 70000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 30000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 15000,
+ .tDH_min = 5000,
+ .tDS_min = 7000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 20000,
+ .tREA_max = 16000,
+ .tREH_min = 7000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 5000,
+ .tRP_min = 10000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 20000,
+ .tWH_min = 7000,
+ .tWHR_min = 80000,
+ .tWP_min = 10000,
+ .tWW_min = 100000,
+ },
+};
+
+/**
+ * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
+ * timings according to the given ONFI timing mode
+ * @mode: ONFI timing mode
+ */
+const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
+{
+ if (mode < 0 || mode > ARRAY_SIZE(onfi_sdr_timings))
+ return ERR_PTR(-EINVAL);
+
+ return &onfi_sdr_timings[mode];
+}
+EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 67f0829..c70e0a3 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -806,6 +806,7 @@ static inline bool nand_is_slc(struct nand_chip *chip)
return chip->bits_per_cell == 1;
}
+
/**
* struct nand_sdr_timings - SDR NAND chip timings
*
@@ -854,4 +855,7 @@ struct nand_sdr_timings {
u32 tWW_min;
};
+/* convert an ONFI timing mode to its timing characteristics. */
+const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+
#endif /* __LINUX_MTD_NAND_H */
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 04/14] mtd: nand: define struct nand_timings
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Define a struct containing the standard NAND timings as described in NAND
datasheets.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
include/linux/mtd/nand.h | 49 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 9e6c8f9..67f0829 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -805,4 +805,53 @@ static inline bool nand_is_slc(struct nand_chip *chip)
{
return chip->bits_per_cell == 1;
}
+
+/**
+ * struct nand_sdr_timings - SDR NAND chip timings
+ *
+ * This struct defines the timing requirements of a SDR NAND chip.
+ * These informations can be found in every NAND datasheets and the timings
+ * meaning are described in the ONFI specifications:
+ * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf? (chapter 4.15 Timing
+ * Parameters)
+ *
+ */
+
+struct nand_sdr_timings {
+ u32 tALH_min;
+ u32 tADL_min;
+ u32 tALS_min;
+ u32 tAR_min;
+ u32 tCEA_max;
+ u32 tCEH_min;
+ u32 tCH_min;
+ u32 tCHZ_max;
+ u32 tCLH_min;
+ u32 tCLR_min;
+ u32 tCLS_min;
+ u32 tCOH_min;
+ u32 tCS_min;
+ u32 tDH_min;
+ u32 tDS_min;
+ u32 tFEAT_max;
+ u32 tIR_min;
+ u32 tITC_max;
+ u32 tRC_min;
+ u32 tREA_max;
+ u32 tREH_min;
+ u32 tRHOH_min;
+ u32 tRHW_min;
+ u32 tRHZ_max;
+ u32 tRLOH_min;
+ u32 tRP_min;
+ u32 tRR_min;
+ u64 tRST_max;
+ u32 tWB_max;
+ u32 tWC_min;
+ u32 tWH_min;
+ u32 tWHR_min;
+ u32 tWP_min;
+ u32 tWW_min;
+};
+
#endif /* __LINUX_MTD_NAND_H */
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 03/14] of: mtd: add documentation for nand-ecc-level property
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
nand-ecc-level property statically defines NAND chip's ECC requirements.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
Documentation/devicetree/bindings/mtd/nand.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index 03855c8..0c962296 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -3,5 +3,8 @@
- nand-ecc-mode : String, operation mode of the NAND ecc mode.
Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
"soft_bch".
+- nand-ecc-level : Two cells property defining the ECC level requirements.
+ The first cell represent the strength and the second cell the ECC block size.
+ E.g. : nand-ecc-level = <4 512>; /* 4 bits / 512 bytes */
- nand-bus-width : 8 or 16 bus width if not present 8
- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 02/14] of: mtd: add NAND ECC level requirements retrieval
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
Some chip do not support automatic retrieval of ECC level requirements.
Provide an helper function to retrieve these requirements from DT.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
drivers/of/of_mtd.c | 25 +++++++++++++++++++++++++
include/linux/of_mtd.h | 7 +++++++
2 files changed, 32 insertions(+)
diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
index a27ec94..e8ced61 100644
--- a/drivers/of/of_mtd.c
+++ b/drivers/of/of_mtd.c
@@ -50,6 +50,31 @@ int of_get_nand_ecc_mode(struct device_node *np)
EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
/**
+ * of_get_nand_ecc_level - Get nand ecc level for the given device_node
+ * @np: Pointer to the given device_node
+ * @strengh: ECC strength
+ * @blk_size: ECC block size
+ *
+ * The function gets ecc level requirements from property 'nand-ecc-level'.
+ * Return 0 on success, -errno otherwise.
+ */
+int of_get_nand_ecc_level(struct device_node *np, u32 *strengh, u32 *blk_size)
+{
+ int err;
+
+ err = of_property_read_u32_index(np, "nand-ecc-level", 0, strengh);
+ if (err < 0)
+ return err;
+
+ err = of_property_read_u32_index(np, "nand-ecc-level", 1, blk_size);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_level);
+
+/**
* of_get_nand_bus_width - Get nand bus witdh for given device_node
* @np: Pointer to the given device_node
*
diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h
index 6f10e93..3bd8c3b 100644
--- a/include/linux/of_mtd.h
+++ b/include/linux/of_mtd.h
@@ -13,6 +13,7 @@
#include <linux/of.h>
int of_get_nand_ecc_mode(struct device_node *np);
+int of_get_nand_ecc_level(struct device_node *np, u32 *strengh, u32 *blk_size);
int of_get_nand_bus_width(struct device_node *np);
bool of_get_nand_on_flash_bbt(struct device_node *np);
@@ -23,6 +24,12 @@ static inline int of_get_nand_ecc_mode(struct device_node *np)
return -ENOSYS;
}
+static inline int of_get_nand_ecc_level(struct device_node *np, u32 *strengh,
+ u32 *blk_size)
+{
+ return -ENOSYS;
+}
+
static inline int of_get_nand_bus_width(struct device_node *np)
{
return -ENOSYS;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 01/14] mtd: nand: retrieve ECC requirements from Hynix READ ID byte 4
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391006064-28890-1-git-send-email-b.brezillon.dev@gmail.com>
The Hynix nand flashes store their ECC requirements in byte 4 of its id
(returned on READ ID command).
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
---
drivers/mtd/nand/nand_base.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index bd39f7b..15069ec 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3202,6 +3202,43 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
else
mtd->erasesize = (64 * 1024) << tmp;
*busw = 0;
+
+ /* Retrieve ECC infos */
+ switch ((id_data[4] >> 4) & 0x7) {
+ case 1:
+ chip->ecc_step_ds = 512;
+ chip->ecc_strength_ds = 1;
+ break;
+ case 2:
+ chip->ecc_step_ds = 512;
+ chip->ecc_strength_ds = 2;
+ break;
+ case 3:
+ chip->ecc_step_ds = 512;
+ chip->ecc_strength_ds = 4;
+ break;
+ case 4:
+ chip->ecc_step_ds = 512;
+ chip->ecc_strength_ds = 8;
+ break;
+ case 5:
+ chip->ecc_step_ds = 1024;
+ chip->ecc_strength_ds = 24;
+ break;
+ case 6:
+ chip->ecc_step_ds = 1024;
+ chip->ecc_strength_ds = 32;
+ break;
+ case 7:
+ chip->ecc_step_ds = 1024;
+ chip->ecc_strength_ds = 40;
+ break;
+ case 0:
+ default:
+ chip->ecc_step_ds = 0;
+ chip->ecc_strength_ds = 0;
+ break;
+ }
} else {
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v2 00/14] mtd: nand: add sunxi NAND Flash Controller support
From: Boris BREZILLON @ 2014-01-29 14:34 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
This series adds support for the sunxi NAND Flash Controller (NFC).
This controller supports up to 8 NAND chip connected.
I'm still in the early stages drivers development and some key features are
missing, but it's usable (I tested it on the cubietruck board).
Here's what's missing:
- DMA support
- HW randomization support
- other improvements ?
This series depends on Emilio's patch series implementing mod0 clks
(http://lists.infradead.org/pipermail/linux-arm-kernel/2013-July/185478.html)
+ an other patch not yet posted
(http://git.elopez.com.ar/linux/commits/5b4eb3ac406b9c98965714d40e8dd6da943d1ab0)
Best Regards,
Boris
Changes since v1:
- add HW ECC support
- rework NAND timings retrieval (use ONFI timing mode instead of raw timings)
- add nand-ecc-level property to specify NAND ECC requirements from DT
Boris BREZILLON (14):
mtd: nand: retrieve ECC requirements from Hynix READ ID byte 4
of: mtd: add NAND ECC level requirements retrieval
of: mtd: add documentation for nand-ecc-level property
mtd: nand: define struct nand_timings
mtd: nand: add ONFI timing mode to nand_timings converter
of: mtd: add NAND timing mode retrieval support
of: mtd: add documentation for the ONFI NAND timing mode property
mtd: nand: add sunxi NAND flash controller support
mtd: nand: add sunxi NFC dt bindings doc
ARM: dt/sunxi: add NFC node to Allwinner A20 SoC
ARM: dt/sunxi: add NFC pinctrl pin definitions
ARM: sunxi/dt: enable NAND on cubietruck board
mtd: nand: add sunxi HW ECC support
ARM: sunxi/dt: enable HW ECC on cubietruck board
Documentation/devicetree/bindings/mtd/nand.txt | 8 +
.../devicetree/bindings/mtd/sunxi-nand.txt | 46 +
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 31 +
arch/arm/boot/dts/sun7i-a20.dtsi | 35 +
drivers/mtd/nand/Kconfig | 6 +
drivers/mtd/nand/Makefile | 3 +-
drivers/mtd/nand/nand_base.c | 37 +
drivers/mtd/nand/nand_timings.c | 248 +++++
drivers/mtd/nand/sunxi_nand.c | 997 ++++++++++++++++++++
drivers/of/of_mtd.c | 44 +
include/linux/mtd/nand.h | 53 ++
include/linux/of_mtd.h | 15 +
12 files changed, 1522 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt
create mode 100644 drivers/mtd/nand/nand_timings.c
create mode 100644 drivers/mtd/nand/sunxi_nand.c
--
1.7.9.5
^ permalink raw reply
* [PATCH] ARM: iop32x: fix reset handling for the EM7210 board
From: Arnd Bergmann @ 2014-01-29 14:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390999545-31428-1-git-send-email-linus.walleij@linaro.org>
On Wednesday 29 January 2014, Linus Walleij wrote:
> This board was missed when converting all the others to proper
> abstracted GPIO handling. Fix it up the right way by requesting
> and driving GPIO line 0 high through gpiolib to reset the machine.
>
> Reported-by: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Thanks for the prompt resolution. Aside from what Arnaud mentioned,
Acked-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply
* [RFC] arm: vdso: Convert sigpage to vdso implementation
From: Steve Capper @ 2014-01-29 14:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140128171015.GM15937@n2100.arm.linux.org.uk>
On Tue, Jan 26, 2014 at 05:10:15PM +0000, Russell King - ARM Linux wrote:
> On Tue, Jan 28, 2014 at 04:25:08PM +0000, Steve Capper wrote:
> > ARM has a special sigpage that is used for signal return trampolines.
> > Its implementation is very similar to a VDSO conceptually in that it
> > occupies a special mapping in user address space.
> >
> > One could actually host the trampoline code in a VDSO instead with the
> > added advantage that one could also host specialised routines there.
> > One such routine could be gettimeofday where on ARM we have architected
> > (and some vendor supplied) timers that can be queried entirely in
> > userspace, obviating the need for an expensive syscall.
> >
> > This patch converts the sigpage implementation to a VDSO. It is mostly
> > a direct port from Will Deacon's arm64 implementation with the ARM
> > signal trampoline plumbed in.
> >
> > Signed-off-by: Steve Capper <steve.capper@linaro.org>
> > ---
> > As can be inferred from this RFC, I am interested ultimately in
> > implementing a syscall-less gettimeofday for ARM. Whilst researching
> > possible vectors page or VDSO implementations, I came across the
> > sigpage mechanism which is very similar to a VDSO.
> >
> > The very simple function, __kernel_vdso_doubler, resolved in a test
> > program automatically on my Arndale board (running Fedora 20) without
> > any additional prodding.
> >
> > IPC stress tests from LTP were executed to test the signal trampoline.
> >
> > I would appreciate any comments on this approach of converting the
> > sigpage to a VDSO. If this looks sane to people, I will work on the
> > gettimeofday logic in a later patch.
>
> I'm not happy with this removing much of the work I pushed into the
> kernel to work around the security issues which were identified with
> the fixed-address placement of stuff in the vectors page. Particularly
> the random placement of the signal return stubs within the new signal
> page is gone with the VDSO approach, which means if someone can discover
> the VDSO page, they can issue any system call they please by knowing
> the appropriate offset into the page to call.
Hi Russell,
I didn't mean to undo you work.
Essentially I saw the sigpage was so close to being a vdso, it just
needed a little nudge to contain other code too.
>
> While the VDSO page will be placed randomly, I'd also like to have the
> signal handlers placed randomly within that page as well - there's no
> need for them to be at a fixed offset. The only thing which needs to
> know where they are after all is the kernel.
I was considering a larger segment containing the trampoline at random
offset, but came to the conclusion that the VA randomisation of the
vdso page location was in itself sufficient?
>
> I'm not sure about putting gettimeofday() into this - gettimeofday()
> would need to have various kernel variables exported into userspace
> for the VDSO page to then compute the current time of day from the
> timer value(s), and that's certainly not going to be at a fixed
> address.
I believe a vdso data page could house the variables, the offsets
within the page could be fixed at compile time.
>
> I believe x86 eventually ended up going down the path of trapping and
> emulating calls to the VDSO page because VDSO became too much of a
> problem (though I think it does provide the option for having it back
> but not by default.)
Cheers,
--
Steve
^ permalink raw reply
* [PATCH v2] ARM: iop32x: fix power off handling for the EM7210 board
From: Linus Walleij @ 2014-01-29 14:20 UTC (permalink / raw)
To: linux-arm-kernel
This board was missed when converting all the others to proper
abstracted GPIO handling. Fix it up the right way by requesting
and driving GPIO line 0 high through gpiolib to power off the
machine.
Cc: Arnaud Patard <arnaud.patard@rtp-net.org>
Reported-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v1->v2:
- Request the power off and set the power off hook with a
device_initcall() so we know the GPIO driver is available
when requesting the line.
- Refer to POWER OFF rather than RESET everywhere.
ARM SoC folks, if you're happy with this fix, please apply it
directly to fixes in the ARM SoC tree.
---
arch/arm/mach-iop32x/em7210.c | 32 +++++++++++++++++++++++++++-----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
index 177cd073a83b..77e1ff057303 100644
--- a/arch/arm/mach-iop32x/em7210.c
+++ b/arch/arm/mach-iop32x/em7210.c
@@ -23,6 +23,7 @@
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/gpio.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -176,11 +177,35 @@ static struct platform_device em7210_serial_device = {
.resource = &em7210_uart_resource,
};
+#define EM7210_HARDWARE_POWER 0
+
void em7210_power_off(void)
{
- *IOP3XX_GPOE &= 0xfe;
- *IOP3XX_GPOD |= 0x01;
+ int ret;
+
+ ret = gpio_direction_output(EM7210_HARDWARE_POWER, 1);
+ if (ret)
+ pr_crit("could not drive power off GPIO high\n");
+}
+
+static int __init em7210_request_gpios(void)
+{
+ int ret;
+
+ if (!machine_is_em7210())
+ return 0;
+
+ ret = gpio_request(EM7210_HARDWARE_POWER, "power");
+ if (ret) {
+ pr_err("could not request power off GPIO\n");
+ return 0;
+ }
+
+ pm_power_off = em7210_power_off;
+
+ return 0;
}
+device_initcall(em7210_request_gpios);
static void __init em7210_init_machine(void)
{
@@ -194,9 +219,6 @@ static void __init em7210_init_machine(void)
i2c_register_board_info(0, em7210_i2c_devices,
ARRAY_SIZE(em7210_i2c_devices));
-
-
- pm_power_off = em7210_power_off;
}
MACHINE_START(EM7210, "Lanner EM7210")
--
1.8.5.3
^ permalink raw reply related
* [PATCH v3 02/11] iommu/arm-smmu: Introduce iommu_group notifier block
From: Andreas Herrmann @ 2014-01-29 14:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <991cc0024ea54cdb964f31de89c0b0ea@BL2PR03MB468.namprd03.prod.outlook.com>
On Tue, Jan 28, 2014 at 11:00:35AM +0000, Varun Sethi wrote:
>
>
> > -----Original Message-----
> > From: iommu-bounces at lists.linux-foundation.org [mailto:iommu-
> > bounces at lists.linux-foundation.org] On Behalf Of Andreas Herrmann
> > Sent: Friday, January 24, 2014 1:27 AM
> > To: Sethi Varun-B16395
> > Cc: Andreas Herrmann; iommu at lists.linux-foundation.org; Will Deacon;
> > linux-arm-kernel at lists.infradead.org
> > Subject: Re: [PATCH v3 02/11] iommu/arm-smmu: Introduce iommu_group
> > notifier block
> >
> > On Wed, Jan 22, 2014 at 07:07:40PM +0000, Varun Sethi wrote:
> > > > -----Original Message-----
> > > > From: Will Deacon [mailto:will.deacon at arm.com]
> > > > Sent: Wednesday, January 22, 2014 9:04 PM
> > > > To: Sethi Varun-B16395
> > > > Cc: Andreas Herrmann; iommu at lists.linux-foundation.org; linux-arm-
> > > > kernel at lists.infradead.org; Andreas Herrmann
> > > > Subject: Re: [PATCH v3 02/11] iommu/arm-smmu: Introduce iommu_group
> > > > notifier block
> > > >
> > > > On Wed, Jan 22, 2014 at 01:54:11PM +0000, Varun Sethi wrote:
> > > > > > > > Ok, so are you suggesting that we perform the isolation
> > > > > > > > mapping in arm_smmu_add_device and drop the notifier
> > altogether?
> > > > > > > I think that should be fine, until we want to delay mapping
> > > > > > > creation till driver bind time.
> > > > > >
> > > > > > Is there a hard dependency on that?
> > > > > >
> > > > > Not sure, may be Andreas can answer that.
> > > >
> > > > Ok. Andreas? I would have thought doing this *earlier* shouldn't be
> > > > a problem (the DMA ops must be swizzled before the driver is probed).
> > > >
> > > > > > > But the "isolate device" property should dictate iommu group
> > > > creation.
> > > > > >
> > > > > > The reason we added automatic group creation (per-device) is for
> > > > > > VFIO, which expects all devices to be in a group regardless of
> > > > > > the device isolation configuration.
> > > > > >
> > > > > IIUC, with the "isolate devices" property we ensure that there
> > > > > would be independent SMR and S2CR per device. Is that correct?
> > > >
> > > > Yes, as part of giving them independent sets of page tables.
> > > > Initially these tables don't have any valid mappings, but the
> > > > dma-mapping API will populate them in response to
> > dma_map_*/dma_alloc/etc.
> > > >
> > > > Not sure what this has to do with us putting devices into their own
> > > > groups...
> >
> > > [Sethi Varun-B16395] Devices in an iommu group would share the dma
> > > mapping, so shouldn't they be sharing the SMR and context registers?
> >
> > I aggree with the context but SMRs won't be shared. I think you just can
> > say that a certain subset of the available SMRs will be used to map all
> > devices in an iommu group to the same context. Depending on what
> > streamIDs each device has you might have to use separate SMRs for each
> > device to map it to the same context.
> [Sethi Varun-B16395] IIUC the SMRs would unique per device, but
> there is a possibility where the number of context registers are
> restricted? In that case IOMMU groups should correspond to unique
> stream IDs (and corresponding SMRs).
> > > In case of the "isolate devices" property, each device would have its
> > > own SMR and context registers, thus allowing the devices to have
> > > independent mappings and allowing them to fall in separate iommu
> > > groups.
> >
> > I aggree with Varun's view here. (Now that I take iommu groups into
> > consideration.)
> >
> > But my goal with the "isolate devices" thing was twofold:
> >
> > 1. actual make use of SMMU for address translation for all master
> > devices (instead of just bypassing the SMMU)
> [Sethi Varun-B16395] even if masters have to share translation? But
> from the patch it seemed that we are creating mapping only if we
> find the isolate devices property.
Yes, the patch creates mappings only if isolate-devices property is
given. Currently there is no trigger to create a common mapping for
all devices attached to the same SMMU.
> > plus
> >
> > 2. put each master into it's own domain to isolate it
> >
> > The latter matches usage of separate iommu groups for devices. If we now
> > use the isolate devices property to just control whether master devices
> > fall into the same or separate iommu groups it seems to me we would need
> > to have another mechanism that triggers the creation of a mapping for a
> > group.
> >
> > What do you think?
> >
> [Sethi Varun-B16395] As mentioned before, we should be having iommu
> group per device (having a unique stream id). Isolate devices
> property just ensures that each device has a unique context. Now,
> for the devices for which we don't have the isolate device property,
> can't we have the multiple devices point to a common mapping.
Hmm, the isolate-devices option is per SMMU. So if this is set for an
SMMU the driver tries to create a mapping per device. (And this is
done for all master devices of this SMMU.)
Are you requesting to change the default behaviour of the driver to
create a shared mapping in case the isolate-devices property is not
specified in DT for an SMMU node?
Or maybe your concern is that you have x master devices for an SMMU
which support y number of contexts and x > y? Which would imply that
not all devices can be isolated and some need to share a context?
Andreas
^ permalink raw reply
* [PATCH] ARM: iop32x: fix reset handling for the EM7210 board
From: Linus Walleij @ 2014-01-29 14:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87txcneyi6.fsf@lebrac.rtp-net.org>
On Wed, Jan 29, 2014 at 1:57 PM, Arnaud Patard
<arnaud.patard@rtp-net.org> wrote:
> Linus Walleij <linus.walleij@linaro.org> writes:
>
> don't know how to comment about the subjet but it's _not_ about
> resetting the board but about powering it off.
Aha sorry I'll respin with updated text.
>> register_iop32x_gpio();
>> platform_device_register(&em7210_serial_device);
>> platform_device_register(&iop3xx_i2c0_device);
>> @@ -194,7 +202,9 @@ static void __init em7210_init_machine(void)
>>
>> i2c_register_board_info(0, em7210_i2c_devices,
>> ARRAY_SIZE(em7210_i2c_devices));
>> -
>> + ret = gpio_request(EM7210_HARDWARE_RESET, "reset");
>> + if (ret)
>> + pr_err("could not request reset GPIO\n");
>
> no chance to work. too early. you'll get a -EPROBE_DEFER.
Yeah that's right, I remember now that I added a separate
device_initcall() on the N2100 for this. Thanks, I'll respin that.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v3] ARM: hw_breakpoint: Add ARMv8 support
From: Christopher Covington @ 2014-01-29 14:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140129105722.GD26622@mudshark.cambridge.arm.com>
Hi Will,
On 01/29/2014 05:57 AM, Will Deacon wrote:
> Hi Christopher,
>
> On Tue, Jan 28, 2014 at 06:51:51PM +0000, Christopher Covington wrote:
>> Add the trivial support necessary to get hardware breakpoints
>> working for GDB on ARMv8 simulators running in AArch32 mode.
>>
>> Acked-by: Will Deacon <will.deacon@arm.com>
>> Signed-off-by: Christopher Covington <cov@codeaurora.org>
>> ---
>>
>> v3: assume for now that ARMv9 and later will update FSR
>
> Please can you stick this into the patch system? I don't have any other
> hw_breakpoint changes queued, so I doubt I'll send a pull for 3.15.
Thanks for your review. Sounds good; will do.
Regards,
Christopher
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by the Linux Foundation.
^ permalink raw reply
* [PATCH v2 3/5] spi: sunxi: Add Allwinner A31 SPI controller driver
From: Maxime Ripard @ 2014-01-29 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140129122520.GY11841@sirena.org.uk>
On Wed, Jan 29, 2014 at 12:25:20PM +0000, Mark Brown wrote:
> On Wed, Jan 29, 2014 at 12:10:48PM +0100, Maxime Ripard wrote:
>
> > +config SPI_SUN6I
> > + tristate "Allwinner A31 SPI controller"
> > + depends on ARCH_SUNXI || COMPILE_TEST
> > + select PM_RUNTIME
> > + help
> > + This enables using the SPI controller on the Allwinner A31 SoCs.
> > +
>
> A select of PM_RUNTIME is both surprising and odd - why is that there?
> The usual idiom is that the device starts out powered up (flagged using
> pm_runtime_set_active()) and then runtime PM then suspends it when it's
> compiled in. That way if for some reason people want to avoid runtime
> PM they can still use the device.
Since pm_runtime_set_active and all the pm_runtime* callbacks in
general are defined to pretty much empty functions, how the
suspend/resume callbacks are called then? Obviously, we need them to
be run, hence why I added the select here, but now I'm seeing a
construct like what's following acceptable then?
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev))
sun6i_spi_runtime_resume(&pdev->dev);
> > +static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
> > +{
> > + struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
> > + u32 reg;
> > +
> > + if (!enable)
> > + return;
> > +
> > + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
> > + reg &= ~SUN6I_TFR_CTL_CS_MASK;
> > + reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
> > + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
> > +}
>
> The !enable means that it'll only ever be able to go one way. Also note
> that the documentation was clarified here to make the enable flag be the
> absolute logic level, not if chip select was asserted.
Actually the IP asserts the CS automatically, the only thing you need
to do is to set which CS to use for your next transfer in some
register (which is what I'm doing after the !enable), and the CS will
be managed directly by the controller. Hence, there's no way to say
wether you want to enable it or not.
The controller allows to control the CS manually also, if that's the
preferred way of doing things.
> > + timeout = wait_for_completion_timeout(&sspi->done,
> > + msecs_to_jiffies(1000));
> > + if (!timeout) {
> > + ret = -ETIMEDOUT;
> > + goto out;
> > + }
> > +
> > + sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
>
> This means we can only transfer a single FIFO of data? I didn't see a
> check on the transfer length.
At the moment, indeed. And that's the first thing I check in the
transfer_one function.
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140129/f8b2b915/attachment-0001.sig>
^ permalink raw reply
* [PATCH] ARM: dts: Add basic devices for AM3517-craneboard
From: Nishanth Menon @ 2014-01-29 13:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52DD522E.1070607@ti.com>
On 01/20/2014 10:43 AM, Nishanth Menon wrote:
> Benoit,
>
> On 12/18/2013 11:16 AM, Benoit Cousson wrote:
>> On 18/12/2013 18:02, Nishanth Menon wrote:
>>> On 12/18/2013 10:57 AM, Benoit Cousson wrote:
>>>> On 17/12/2013 20:45, Nishanth Menon wrote:
>>>>> On 12/09/2013 03:55 PM, Nishanth Menon wrote:
>>>>>> Craneboard is a hardware development platform based on the Sitara
>>>>>> AM3517 ARM Cortex - A8 microprocessor device - see [1] for more
>>>>>> details. Add basic devices for craneboard as replacement for the board
>>>>>> file scheduled for removal as part of device tree conversion
>>>>>>
>>>>>> [1] http://craneboard.org
>>>>>>
>>>>>> Signed-off-by: Nishanth Menon <nm@ti.com>
>>>>>> ---
>>>>>
>>>>> gentle ping.. had'nt seen a response on this patch. Could we queue
>>>>> this up for v3.14-rc1?
>>>>
>>>> Yep, it looks good to me.
>>> Thanks benoit.
>>>
>>>> But if you don't mind I'll start pushing my branch after Xmas :-).
>>>
>>> As long as Tony is ok with it, I have no issues either - will be great
>>> to have dt only boot in .14-rc1 though.
>>
>> Good point, it is already -rc4.
>>
>> OK, I'll just queued it and pushed it to for_3.14/dts.
>
> I dont see this in next-20140120 yet - wondering if Tony or you have
> plans for one of .14 rcs OR if this is queued for .15.
gentle ping yet again :(
--
Regards,
Nishanth Menon
^ permalink raw reply
* [PATCH] ARM: OMAP2+: add missing ARCH_HAS_OPP
From: Nishanth Menon @ 2014-01-29 13:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389816038-17363-1-git-send-email-nm@ti.com>
Hi Tony,
On 01/15/2014 02:00 PM, Nishanth Menon wrote:
> OMAP5, DRA7, AM43xx all have OPPs. So select the same to allow SoC
> only configuration boot to work with OPP.
>
> Reported-by: Nikhil Devshatwar <nikhil.nd@ti.com>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>
> For DRA7, depends on: https://patchwork.kernel.org/patch/3465411/
Considering that dependent patch is now on linus master,
a gentle ping -> The patch does apply on latest linus master commit
0e47c969c65e213421450c31043353ebe3c67e0c
patchworks reference: https://patchwork.kernel.org/patch/3493581/
>
> arch/arm/mach-omap2/Kconfig | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> index 35c23e5..66a9c4a 100644
> --- a/arch/arm/mach-omap2/Kconfig
> +++ b/arch/arm/mach-omap2/Kconfig
> @@ -50,6 +50,7 @@ config SOC_OMAP5
> bool "TI OMAP5"
> depends on ARCH_MULTI_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select ARM_CPU_SUSPEND if PM
> select ARM_GIC
> select CPU_V7
> @@ -63,6 +64,7 @@ config SOC_AM33XX
> bool "TI AM33XX"
> depends on ARCH_MULTI_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select ARM_CPU_SUSPEND if PM
> select CPU_V7
> select MULTI_IRQ_HANDLER
> @@ -72,6 +74,7 @@ config SOC_AM43XX
> depends on ARCH_MULTI_V7
> select CPU_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select MULTI_IRQ_HANDLER
> select ARM_GIC
> select MACH_OMAP_GENERIC
> @@ -80,6 +83,7 @@ config SOC_DRA7XX
> bool "TI DRA7XX"
> depends on ARCH_MULTI_V7
> select ARCH_OMAP2PLUS
> + select ARCH_HAS_OPP
> select ARM_CPU_SUSPEND if PM
> select ARM_GIC
> select CPU_V7
>
--
Regards,
Nishanth Menon
^ permalink raw reply
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