| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- From 074036f9de6b8c5fc642e8e2540950f6a35aa804 Mon Sep 17 00:00:00 2001
- From: Ram Chandra Jangir <[email protected]>
- Date: Thu, 20 Apr 2017 10:31:10 +0530
- Subject: [PATCH] qcom: mtd: nand: Add bam_dma support in qcom_nand driver
- The current driver only support ADM DMA so this patch adds the
- BAM DMA support in current NAND driver with compatible string
- qcom,ebi2-nandc-bam.
- Added bam channels and data buffers, NAND BAM uses 3 channels:
- command, data tx and data rx, while ADM uses only single channel.
- So this patch adds the BAM channel in device tree and using the
- same in NAND driver allocation function.
- Signed-off-by: Ram Chandra Jangir <[email protected]>
- ---
- .../devicetree/bindings/mtd/qcom_nandc.txt | 69 +++++++--
- drivers/mtd/nand/qcom_nandc.c | 160 +++++++++++++++++----
- 2 files changed, 190 insertions(+), 39 deletions(-)
- --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
- +++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
- @@ -1,21 +1,26 @@
- * Qualcomm NAND controller
-
- Required properties:
- -- compatible: should be "qcom,ipq806x-nand"
- +- compatible: "qcom,ipq806x-nand" for IPQ8064 which uses
- + ADM DMA.
- + "qcom,ebi2-nand-bam" - nand drivers using BAM DMA
- + like IPQ4019.
- - reg: MMIO address range
- - clocks: must contain core clock and always on clock
- - clock-names: must contain "core" for the core clock and "aon" for the
- always on clock
- - dmas: DMA specifier, consisting of a phandle to the ADM DMA
- - controller node and the channel number to be used for
- - NAND. Refer to dma.txt and qcom_adm.txt for more details
- -- dma-names: must be "rxtx"
- -- qcom,cmd-crci: must contain the ADM command type CRCI block instance
- - number specified for the NAND controller on the given
- - platform
- -- qcom,data-crci: must contain the ADM data type CRCI block instance
- - number specified for the NAND controller on the given
- - platform
- + or BAM DMA controller node and the channel number to
- + be used for NAND. Refer to dma.txt, qcom_adm.txt(ADM)
- + and qcom_bam_dma.txt(BAM) for more details
- +- dma-names: "rxtx" - ADM
- + "tx", "rx", "cmd" - BAM
- +- qcom,cmd-crci: Only required for ADM DMA. must contain the ADM command
- + type CRCI block instance number specified for the NAND
- + controller on the given platform.
- +- qcom,data-crci: Only required for ADM DMA. must contain the ADM data
- + type CRCI block instance number specified for the NAND
- + controller on the given platform.
- - #address-cells: <1> - subnodes give the chip-select number
- - #size-cells: <0>
-
- @@ -44,7 +49,7 @@ partition.txt for more detail.
- Example:
-
- nand@1ac00000 {
- - compatible = "qcom,ebi2-nandc";
- + compatible = "qcom,ipq806x-nand","qcom.qcom_nand";
- reg = <0x1ac00000 0x800>;
-
- clocks = <&gcc EBI2_CLK>,
- @@ -58,6 +63,48 @@ nand@1ac00000 {
-
- #address-cells = <1>;
- #size-cells = <0>;
- +
- + nandcs@0 {
- + compatible = "qcom,nandcs";
- + reg = <0>;
- +
- + nand-ecc-strength = <4>;
- + nand-ecc-step-size = <512>;
- + nand-bus-width = <8>;
- +
- + partitions {
- + compatible = "fixed-partitions";
- + #address-cells = <1>;
- + #size-cells = <1>;
- +
- + partition@0 {
- + label = "boot-nand";
- + reg = <0 0x58a0000>;
- + };
- +
- + partition@58a0000 {
- + label = "fs-nand";
- + reg = <0x58a0000 0x4000000>;
- + };
- + };
- + };
- +};
- +
- +nand@79B0000 {
- + compatible = "qcom,ebi2-nandc-bam";
- + reg = <0x79B0000 0x1000>;
- +
- + clocks = <&gcc EBI2_CLK>,
- + <&gcc EBI2_AON_CLK>;
- + clock-names = "core", "aon";
- +
- + dmas = <&qpicbam 0>,
- + <&qpicbam 1>,
- + <&qpicbam 2>;
- + dma-names = "tx", "rx", "cmd";
- +
- + #address-cells = <1>;
- + #size-cells = <0>;
-
- nandcs@0 {
- compatible = "qcom,nandcs";
- --- a/drivers/mtd/nand/qcom_nandc.c
- +++ b/drivers/mtd/nand/qcom_nandc.c
- @@ -234,6 +234,7 @@ struct nandc_regs {
- * by upper layers directly
- * @buf_size/count/start: markers for chip->read_buf/write_buf functions
- * @reg_read_buf: local buffer for reading back registers via DMA
- + * @reg_read_buf_phys: contains dma address for register read buffer
- * @reg_read_pos: marker for data read in reg_read_buf
- *
- * @regs: a contiguous chunk of memory for DMA register
- @@ -242,7 +243,10 @@ struct nandc_regs {
- * @cmd1/vld: some fixed controller register values
- * @ecc_modes: supported ECC modes by the current controller,
- * initialized via DT match data
- - */
- + * @bch_enabled: flag to tell whether BCH or RS ECC mode is used
- + * @dma_bam_enabled: flag to tell whether nand controller is using
- + * bam dma
- +*/
- struct qcom_nand_controller {
- struct nand_hw_control controller;
- struct list_head host_list;
- @@ -255,17 +259,28 @@ struct qcom_nand_controller {
- struct clk *core_clk;
- struct clk *aon_clk;
-
- - struct dma_chan *chan;
- - unsigned int cmd_crci;
- - unsigned int data_crci;
- struct list_head desc_list;
- + union {
- + struct {
- + struct dma_chan *tx_chan;
- + struct dma_chan *rx_chan;
- + struct dma_chan *cmd_chan;
- + };
- + struct {
- + struct dma_chan *chan;
- + unsigned int cmd_crci;
- + unsigned int data_crci;
- + };
- + };
-
- u8 *data_buffer;
- + bool dma_bam_enabled;
- int buf_size;
- int buf_count;
- int buf_start;
-
- __le32 *reg_read_buf;
- + dma_addr_t reg_read_buf_phys;
- int reg_read_pos;
-
- struct nandc_regs *regs;
- @@ -324,6 +339,17 @@ struct qcom_nand_host {
- u32 clrreadstatus;
- };
-
- +/*
- + * This data type corresponds to the nand driver data which will be used at
- + * driver probe time
- + * @ecc_modes - ecc mode for nand
- + * @dma_bam_enabled - whether this driver is using bam
- + */
- +struct qcom_nand_driver_data {
- + u32 ecc_modes;
- + bool dma_bam_enabled;
- +};
- +
- static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
- {
- return container_of(chip, struct qcom_nand_host, chip);
- @@ -1949,16 +1975,46 @@ static int qcom_nandc_alloc(struct qcom_
- if (!nandc->regs)
- return -ENOMEM;
-
- - nandc->reg_read_buf = devm_kzalloc(nandc->dev,
- - MAX_REG_RD * sizeof(*nandc->reg_read_buf),
- - GFP_KERNEL);
- - if (!nandc->reg_read_buf)
- - return -ENOMEM;
- + if (!nandc->dma_bam_enabled) {
- + nandc->reg_read_buf = devm_kzalloc(nandc->dev,
- + MAX_REG_RD *
- + sizeof(*nandc->reg_read_buf),
- + GFP_KERNEL);
-
- - nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
- - if (!nandc->chan) {
- - dev_err(nandc->dev, "failed to request slave channel\n");
- - return -ENODEV;
- + if (!nandc->reg_read_buf)
- + return -ENOMEM;
- +
- + nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
- + if (!nandc->chan) {
- + dev_err(nandc->dev, "failed to request slave channel\n");
- + return -ENODEV;
- + }
- + } else {
- + nandc->reg_read_buf = dmam_alloc_coherent(nandc->dev,
- + MAX_REG_RD *
- + sizeof(*nandc->reg_read_buf),
- + &nandc->reg_read_buf_phys, GFP_KERNEL);
- +
- + if (!nandc->reg_read_buf)
- + return -ENOMEM;
- +
- + nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx");
- + if (!nandc->tx_chan) {
- + dev_err(nandc->dev, "failed to request tx channel\n");
- + return -ENODEV;
- + }
- +
- + nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx");
- + if (!nandc->rx_chan) {
- + dev_err(nandc->dev, "failed to request rx channel\n");
- + return -ENODEV;
- + }
- +
- + nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd");
- + if (!nandc->cmd_chan) {
- + dev_err(nandc->dev, "failed to request cmd channel\n");
- + return -ENODEV;
- + }
- }
-
- INIT_LIST_HEAD(&nandc->desc_list);
- @@ -1971,8 +2027,35 @@ static int qcom_nandc_alloc(struct qcom_
-
- static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
- {
- - dma_release_channel(nandc->chan);
- -}
- + if (nandc->dma_bam_enabled) {
- + if (nandc->tx_chan)
- + dma_release_channel(nandc->tx_chan);
- +
- + if (nandc->rx_chan)
- + dma_release_channel(nandc->rx_chan);
- +
- + if (nandc->cmd_chan)
- + dma_release_channel(nandc->tx_chan);
- +
- + if (nandc->reg_read_buf)
- + dmam_free_coherent(nandc->dev, MAX_REG_RD *
- + sizeof(*nandc->reg_read_buf),
- + nandc->reg_read_buf,
- + nandc->reg_read_buf_phys);
- + } else {
- + if (nandc->chan)
- + dma_release_channel(nandc->chan);
- +
- + if (nandc->reg_read_buf)
- + devm_kfree(nandc->dev, nandc->reg_read_buf);
- + }
- +
- + if (nandc->regs)
- + devm_kfree(nandc->dev, nandc->regs);
- +
- + if (nandc->data_buffer)
- + devm_kfree(nandc->dev, nandc->data_buffer);
- + }
-
- /* one time setup of a few nand controller registers */
- static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
- @@ -2010,6 +2093,8 @@ static int qcom_nand_host_init(struct qc
- mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
- mtd->owner = THIS_MODULE;
- mtd->dev.parent = dev;
- + mtd->priv = chip;
- + chip->priv = nandc;
-
- chip->cmdfunc = qcom_nandc_command;
- chip->select_chip = qcom_nandc_select_chip;
- @@ -2057,16 +2142,20 @@ static int qcom_nandc_parse_dt(struct pl
- struct device_node *np = nandc->dev->of_node;
- int ret;
-
- - ret = of_property_read_u32(np, "qcom,cmd-crci", &nandc->cmd_crci);
- - if (ret) {
- - dev_err(nandc->dev, "command CRCI unspecified\n");
- - return ret;
- - }
- + if (!nandc->dma_bam_enabled) {
- + ret = of_property_read_u32(np, "qcom,cmd-crci",
- + &nandc->cmd_crci);
- + if (ret) {
- + dev_err(nandc->dev, "command CRCI unspecified\n");
- + return ret;
- + }
-
- - ret = of_property_read_u32(np, "qcom,data-crci", &nandc->data_crci);
- - if (ret) {
- - dev_err(nandc->dev, "data CRCI unspecified\n");
- - return ret;
- + ret = of_property_read_u32(np, "qcom,data-crci",
- + &nandc->data_crci);
- + if (ret) {
- + dev_err(nandc->dev, "data CRCI unspecified\n");
- + return ret;
- + }
- }
-
- return 0;
- @@ -2081,6 +2170,7 @@ static int qcom_nandc_probe(struct platf
- struct device_node *dn = dev->of_node, *child;
- struct resource *res;
- int ret;
- + struct qcom_nand_driver_data *driver_data;
-
- nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
- if (!nandc)
- @@ -2095,7 +2185,10 @@ static int qcom_nandc_probe(struct platf
- return -ENODEV;
- }
-
- - nandc->ecc_modes = (unsigned long)dev_data;
- + driver_data = (struct qcom_nand_driver_data *)dev_data;
- +
- + nandc->ecc_modes = driver_data->ecc_modes;
- + nandc->dma_bam_enabled = driver_data->dma_bam_enabled;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nandc->base = devm_ioremap_resource(dev, res);
- @@ -2187,7 +2280,15 @@ static int qcom_nandc_remove(struct plat
- return 0;
- }
-
- -#define EBI2_NANDC_ECC_MODES (ECC_RS_4BIT | ECC_BCH_8BIT)
- +struct qcom_nand_driver_data ebi2_nandc_bam_data = {
- + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
- + .dma_bam_enabled = true,
- +};
- +
- +struct qcom_nand_driver_data ebi2_nandc_data = {
- + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
- + .dma_bam_enabled = false,
- +};
-
- /*
- * data will hold a struct pointer containing more differences once we support
- @@ -2195,7 +2296,10 @@ static int qcom_nandc_remove(struct plat
- */
- static const struct of_device_id qcom_nandc_of_match[] = {
- { .compatible = "qcom,ipq806x-nand",
- - .data = (void *)EBI2_NANDC_ECC_MODES,
- + .data = (void *) &ebi2_nandc_data,
- + },
- + { .compatible = "qcom,ebi2-nandc-bam",
- + .data = (void *) &ebi2_nandc_bam_data,
- },
- {}
- };
|