* [PATCH RFC v11 5/6] dma: mpc512x: add device tree binding document
From: Alexander Popov @ 2014-04-15 10:54 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
Cc: devicetree
In-Reply-To: <1397559250-17680-1-git-send-email-a13xp0p0v88@gmail.com>
Introduce a device tree binding document for the MPC512x DMA controller
Signed-off-by: Gerhard Sittig <gsi@denx.de>
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
.../devicetree/bindings/dma/mpc512x-dma.txt | 51 ++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/mpc512x-dma.txt
diff --git a/Documentation/devicetree/bindings/dma/mpc512x-dma.txt b/Documentation/devicetree/bindings/dma/mpc512x-dma.txt
new file mode 100644
index 0000000..92eb0d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/mpc512x-dma.txt
@@ -0,0 +1,51 @@
+* Freescale MPC512x and MPC8308 DMA Controller
+
+The DMA controller in the Freescale MPC512x and MPC8308 SoCs can move
+blocks of memory contents between memory and peripherals or
+from memory to memory.
+
+Refer to the "Generic DMA Controller and DMA request bindings" in
+the dma/dma.txt file for a more detailed description of binding.
+
+* DMA controller
+
+Required properties:
+- compatible: Should be one of
+ "fsl,mpc5121-dma"
+ "fsl,mpc8308-dma", "fsl,mpc5121-dma"
+- reg: Address and size of the DMA controller's register set
+- interrupts: Interrupt for the DMA controller. Generic interrupt client node
+ is described in interrupt-controller/interrupts.txt
+
+Optional properties:
+- #dma-cells: The length of the DMA specifier, must be <1> since
+ the DMA controller uses a fixed assignment of request lines
+ per channel. Refer to dma/dma.txt for the detailed description
+ of this property
+
+Example:
+
+ dma0: dma@14000 {
+ compatible = "fsl,mpc5121-dma";
+ reg = <0x14000 0x1800>;
+ interrupts = <65 0x8>;
+ #dma-cells = <1>;
+ };
+
+* DMA client
+
+Required properties:
+- dmas: List of one or more DMA request specifiers. One DMA request specifier
+ consists of a phandle to the DMA controller node followed by
+ the integer specifying the request line
+- dma-names: Contains an identifier string for each DMA request specifier.
+ Refer to dma/dma.txt for the description of this property
+
+Example:
+
+ sdhc@1500 {
+ compatible = "fsl,mpc5121-sdhc";
+ /* ... */
+ dmas = <&dma0 30>;
+ dma-names = "rx-tx";
+ };
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v11 4/6] dma: of: Add common xlate function for matching by channel id
From: Alexander Popov @ 2014-04-15 10:54 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
Cc: devicetree
In-Reply-To: <1397559250-17680-1-git-send-email-a13xp0p0v88@gmail.com>
This patch adds a new common OF dma xlate callback function which will match a
channel by it's id. The binding expects one integer argument which it will use to
lookup the channel by the id.
Unlike of_dma_simple_xlate this function is able to handle a system with
multiple DMA controllers. When registering the of dma provider with
of_dma_controller_register a pointer to the dma_device struct which is
associated with the dt node needs to passed as the data parameter.
New function will use this pointer to match only channels which belong to the
specified DMA controller.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
drivers/dma/of-dma.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/of_dma.h | 4 ++++
2 files changed, 39 insertions(+)
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index e8fe9dc..d5fbeaa 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -218,3 +218,38 @@ struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
&dma_spec->args[0]);
}
EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
+
+/**
+ * of_dma_xlate_by_chan_id - Translate dt property to DMA channel by channel id
+ * @dma_spec: pointer to DMA specifier as found in the device tree
+ * @of_dma: pointer to DMA controller data
+ *
+ * This function can be used as the of xlate callback for DMA driver which wants
+ * to match the channel based on the channel id. When using this xlate function
+ * the #dma-cells propety of the DMA controller dt node needs to be set to 1.
+ * The data parameter of of_dma_controller_register must be a pointer to the
+ * dma_device struct the function should match upon.
+ *
+ * Returns pointer to appropriate dma channel on success or NULL on error.
+ */
+struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct dma_device *dev = ofdma->of_dma_data;
+ struct dma_chan *chan, *candidate = NULL;
+
+ if (!dev || dma_spec->args_count != 1)
+ return NULL;
+
+ list_for_each_entry(chan, &dev->channels, device_node)
+ if (chan->chan_id == dma_spec->args[0]) {
+ candidate = chan;
+ break;
+ }
+
+ if (!candidate)
+ return NULL;
+
+ return dma_get_slave_channel(candidate);
+}
+EXPORT_SYMBOL_GPL(of_dma_xlate_by_chan_id);
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index ae36298..56bc026 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -41,6 +41,8 @@ extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
const char *name);
extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma);
+extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma);
#else
static inline int of_dma_controller_register(struct device_node *np,
struct dma_chan *(*of_dma_xlate)
@@ -66,6 +68,8 @@ static inline struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_s
return NULL;
}
+#define of_dma_xlate_by_chan_id NULL
+
#endif
#endif /* __LINUX_OF_DMA_H */
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v11 3/6] dma: mpc512x: fix freeing resources in mpc_dma_probe() and mpc_dma_remove()
From: Alexander Popov @ 2014-04-15 10:54 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
In-Reply-To: <1397559250-17680-1-git-send-email-a13xp0p0v88@gmail.com>
Fix mpc_dma_probe() error path and mpc_dma_remove(): manually free IRQs and
dispose IRQ mappings before devm_* takes care of other resources.
Moreover replace devm_request_irq() with request_irq() since there is no need
to use it because the original code always frees IRQ manually with
devm_free_irq(). Replace devm_free_irq() with free_irq() accordingly.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
drivers/dma/mpc512x_dma.c | 55 ++++++++++++++++++++++++++++++++---------------
1 file changed, 38 insertions(+), 17 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 68231d9..1b90b3b 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -883,13 +883,15 @@ static int mpc_dma_probe(struct platform_device *op)
mdma = devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERNEL);
if (!mdma) {
dev_err(dev, "Memory exhausted!\n");
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err;
}
mdma->irq = irq_of_parse_and_map(dn, 0);
if (mdma->irq == NO_IRQ) {
dev_err(dev, "Error mapping IRQ!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err;
}
if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) {
@@ -897,14 +899,15 @@ static int mpc_dma_probe(struct platform_device *op)
mdma->irq2 = irq_of_parse_and_map(dn, 1);
if (mdma->irq2 == NO_IRQ) {
dev_err(dev, "Error mapping IRQ!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_dispose1;
}
}
retval = of_address_to_resource(dn, 0, &res);
if (retval) {
dev_err(dev, "Error parsing memory region!\n");
- return retval;
+ goto err_dispose2;
}
regs_start = res.start;
@@ -912,31 +915,34 @@ static int mpc_dma_probe(struct platform_device *op)
if (!devm_request_mem_region(dev, regs_start, regs_size, DRV_NAME)) {
dev_err(dev, "Error requesting memory region!\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_dispose2;
}
mdma->regs = devm_ioremap(dev, regs_start, regs_size);
if (!mdma->regs) {
dev_err(dev, "Error mapping memory region!\n");
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_dispose2;
}
mdma->tcd = (struct mpc_dma_tcd *)((u8 *)(mdma->regs)
+ MPC_DMA_TCD_OFFSET);
- retval = devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0, DRV_NAME,
- mdma);
+ retval = request_irq(mdma->irq, &mpc_dma_irq, 0, DRV_NAME, mdma);
if (retval) {
dev_err(dev, "Error requesting IRQ!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_dispose2;
}
if (mdma->is_mpc8308) {
- retval = devm_request_irq(dev, mdma->irq2, &mpc_dma_irq, 0,
- DRV_NAME, mdma);
+ retval = request_irq(mdma->irq2, &mpc_dma_irq, 0,
+ DRV_NAME, mdma);
if (retval) {
dev_err(dev, "Error requesting IRQ2!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_free1;
}
}
@@ -1022,12 +1028,23 @@ static int mpc_dma_probe(struct platform_device *op)
/* Register DMA engine */
dev_set_drvdata(dev, mdma);
retval = dma_async_device_register(dma);
- if (retval) {
- devm_free_irq(dev, mdma->irq, mdma);
- irq_dispose_mapping(mdma->irq);
- }
+ if (retval)
+ goto err_free2;
return retval;
+
+err_free2:
+ if (mdma->is_mpc8308)
+ free_irq(mdma->irq2, mdma);
+err_free1:
+ free_irq(mdma->irq, mdma);
+err_dispose2:
+ if (mdma->is_mpc8308)
+ irq_dispose_mapping(mdma->irq2);
+err_dispose1:
+ irq_dispose_mapping(mdma->irq);
+err:
+ return retval;
}
static int mpc_dma_remove(struct platform_device *op)
@@ -1036,7 +1053,11 @@ static int mpc_dma_remove(struct platform_device *op)
struct mpc_dma *mdma = dev_get_drvdata(dev);
dma_async_device_unregister(&mdma->dma);
- devm_free_irq(dev, mdma->irq, mdma);
+ if (mdma->is_mpc8308) {
+ free_irq(mdma->irq2, mdma);
+ irq_dispose_mapping(mdma->irq2);
+ }
+ free_irq(mdma->irq, mdma);
irq_dispose_mapping(mdma->irq);
return 0;
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v11 2/6] dma: mpc512x: add support for peripheral transfers
From: Alexander Popov @ 2014-04-15 10:54 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
In-Reply-To: <1397559250-17680-1-git-send-email-a13xp0p0v88@gmail.com>
Introduce support for slave s/g transfer preparation and the associated
device control callback in the MPC512x DMA controller driver, which adds
support for data transfers between memory and peripheral I/O to the
previously supported mem-to-mem transfers.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
drivers/dma/mpc512x_dma.c | 239 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 234 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 2ce248b..68231d9 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -2,6 +2,7 @@
* Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
* Copyright (C) Semihalf 2009
* Copyright (C) Ilya Yanok, Emcraft Systems 2010
+ * Copyright (C) Alexander Popov, Promcontroller 2014
*
* Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
* (defines, structures and comments) was taken from MPC5121 DMA driver
@@ -29,8 +30,17 @@
*/
/*
- * This is initial version of MPC5121 DMA driver. Only memory to memory
- * transfers are supported (tested using dmatest module).
+ * MPC512x and MPC8308 DMA driver. It supports
+ * memory to memory data transfers (tested using dmatest module) and
+ * data transfers between memory and peripheral I/O memory
+ * by means of slave s/g with these limitations:
+ * - chunked transfers (transfers with more than one part) are refused
+ * as long as proper support for scatter/gather is missing;
+ * - transfers on MPC8308 always start from software as this SoC appears
+ * not to have external request lines for peripheral flow control;
+ * - minimal memory <-> I/O memory transfer chunk is 4 bytes and consequently
+ * source and destination addresses must be 4-byte aligned
+ * and transfer size must be aligned on (4 * maxburst) boundary;
*/
#include <linux/module.h>
@@ -189,6 +199,7 @@ struct mpc_dma_desc {
dma_addr_t tcd_paddr;
int error;
struct list_head node;
+ int will_access_peripheral;
};
struct mpc_dma_chan {
@@ -201,6 +212,12 @@ struct mpc_dma_chan {
struct mpc_dma_tcd *tcd;
dma_addr_t tcd_paddr;
+ /* Settings for access to peripheral FIFO */
+ dma_addr_t src_per_paddr;
+ u32 src_tcd_nunits;
+ dma_addr_t dst_per_paddr;
+ u32 dst_tcd_nunits;
+
/* Lock for this structure */
spinlock_t lock;
};
@@ -251,8 +268,23 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
struct mpc_dma_desc *mdesc;
int cid = mchan->chan.chan_id;
- /* Move all queued descriptors to active list */
- list_splice_tail_init(&mchan->queued, &mchan->active);
+ while (!list_empty(&mchan->queued)) {
+ mdesc = list_first_entry(&mchan->queued,
+ struct mpc_dma_desc, node);
+ /*
+ * Grab either several mem-to-mem transfer descriptors
+ * or one peripheral transfer descriptor,
+ * don't mix mem-to-mem and peripheral transfer descriptors
+ * within the same 'active' list.
+ */
+ if (mdesc->will_access_peripheral) {
+ if (list_empty(&mchan->active))
+ list_move_tail(&mdesc->node, &mchan->active);
+ break;
+ } else {
+ list_move_tail(&mdesc->node, &mchan->active);
+ }
+ }
/* Chain descriptors into one transaction */
list_for_each_entry(mdesc, &mchan->active, node) {
@@ -278,7 +310,17 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
if (first != prev)
mdma->tcd[cid].e_sg = 1;
- out_8(&mdma->regs->dmassrt, cid);
+
+ if (mdma->is_mpc8308) {
+ /* MPC8308, no request lines, software initiated start */
+ out_8(&mdma->regs->dmassrt, cid);
+ } else if (first->will_access_peripheral) {
+ /* Peripherals involved, start by external request signal */
+ out_8(&mdma->regs->dmaserq, cid);
+ } else {
+ /* Memory to memory transfer, software initiated start */
+ out_8(&mdma->regs->dmassrt, cid);
+ }
}
/* Handle interrupt on one half of DMA controller (32 channels) */
@@ -596,6 +638,7 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
}
mdesc->error = 0;
+ mdesc->will_access_peripheral = 0;
tcd = mdesc->tcd;
/* Prepare Transfer Control Descriptor for this transaction */
@@ -643,6 +686,189 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
return &mdesc->desc;
}
+static struct dma_async_tx_descriptor *
+mpc_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc = NULL;
+ dma_addr_t per_paddr;
+ u32 tcd_nunits;
+ struct mpc_dma_tcd *tcd;
+ unsigned long iflags;
+ struct scatterlist *sg;
+ size_t len;
+ int iter, i;
+
+ /* Currently there is no proper support for scatter/gather */
+ if (sg_len != 1)
+ return NULL;
+
+ if (!is_slave_direction(direction))
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ spin_lock_irqsave(&mchan->lock, iflags);
+
+ mdesc = list_first_entry(&mchan->free,
+ struct mpc_dma_desc, node);
+ if (!mdesc) {
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+ /* Try to free completed descriptors */
+ mpc_dma_process_completed(mdma);
+ return NULL;
+ }
+
+ list_del(&mdesc->node);
+
+ if (direction == DMA_DEV_TO_MEM) {
+ per_paddr = mchan->src_per_paddr;
+ tcd_nunits = mchan->src_tcd_nunits;
+ } else {
+ per_paddr = mchan->dst_per_paddr;
+ tcd_nunits = mchan->dst_tcd_nunits;
+ }
+
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ if (per_paddr == 0 || tcd_nunits == 0)
+ goto err_prep;
+
+ mdesc->error = 0;
+ mdesc->will_access_peripheral = 1;
+
+ /* Prepare Transfer Control Descriptor for this transaction */
+ tcd = mdesc->tcd;
+
+ memset(tcd, 0, sizeof(struct mpc_dma_tcd));
+
+ if (!IS_ALIGNED(sg_dma_address(sg), 4))
+ goto err_prep;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ tcd->saddr = per_paddr;
+ tcd->daddr = sg_dma_address(sg);
+ tcd->soff = 0;
+ tcd->doff = 4;
+ } else {
+ tcd->saddr = sg_dma_address(sg);
+ tcd->daddr = per_paddr;
+ tcd->soff = 4;
+ tcd->doff = 0;
+ }
+
+ tcd->ssize = MPC_DMA_TSIZE_4;
+ tcd->dsize = MPC_DMA_TSIZE_4;
+
+ len = sg_dma_len(sg);
+ tcd->nbytes = tcd_nunits * 4;
+ if (!IS_ALIGNED(len, tcd->nbytes))
+ goto err_prep;
+
+ iter = len / tcd->nbytes;
+ if (iter >= 1 << 15) {
+ /* len is too big */
+ goto err_prep;
+ }
+ /* citer_linkch contains the high bits of iter */
+ tcd->biter = iter & 0x1ff;
+ tcd->biter_linkch = iter >> 9;
+ tcd->citer = tcd->biter;
+ tcd->citer_linkch = tcd->biter_linkch;
+
+ tcd->e_sg = 0;
+ tcd->d_req = 1;
+
+ /* Place descriptor in prepared list */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ list_add_tail(&mdesc->node, &mchan->prepared);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+ }
+
+ return &mdesc->desc;
+
+err_prep:
+ /* Put the descriptor back */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ list_add_tail(&mdesc->node, &mchan->free);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ return NULL;
+}
+
+static int mpc_dma_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct mpc_dma_chan *mchan;
+ struct mpc_dma *mdma;
+ struct dma_slave_config *cfg;
+ unsigned long flags;
+
+ mchan = dma_chan_to_mpc_dma_chan(chan);
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ /* Disable channel requests */
+ mdma = dma_chan_to_mpc_dma(chan);
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ out_8(&mdma->regs->dmacerq, chan->chan_id);
+ list_splice_tail_init(&mchan->prepared, &mchan->free);
+ list_splice_tail_init(&mchan->queued, &mchan->free);
+ list_splice_tail_init(&mchan->active, &mchan->free);
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ return 0;
+ case DMA_SLAVE_CONFIG:
+ /*
+ * Constraints:
+ * - only transfers between a peripheral device and
+ * memory are supported;
+ * - minimal transfer chunk is 4 bytes and consequently
+ * source and destination addresses must be 4-byte aligned
+ * and transfer size must be aligned on (4 * maxburst)
+ * boundary;
+ * - during the transfer RAM address is being incremented by
+ * the size of minimal transfer chunk;
+ * - peripheral port's address is constant during the transfer.
+ */
+
+ cfg = (void *)arg;
+
+ if (cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
+ cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
+ !IS_ALIGNED(cfg->src_addr, 4) ||
+ !IS_ALIGNED(cfg->dst_addr, 4)) {
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ mchan->src_per_paddr = cfg->src_addr;
+ mchan->src_tcd_nunits = cfg->src_maxburst;
+ mchan->dst_per_paddr = cfg->dst_addr;
+ mchan->dst_tcd_nunits = cfg->dst_maxburst;
+
+ /* Apply defaults */
+ if (mchan->src_tcd_nunits == 0)
+ mchan->src_tcd_nunits = 1;
+ if (mchan->dst_tcd_nunits == 0)
+ mchan->dst_tcd_nunits = 1;
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ return 0;
+ default:
+ /* Unknown command */
+ break;
+ }
+
+ return -ENXIO;
+}
+
static int mpc_dma_probe(struct platform_device *op)
{
struct device_node *dn = op->dev.of_node;
@@ -727,9 +953,12 @@ static int mpc_dma_probe(struct platform_device *op)
dma->device_issue_pending = mpc_dma_issue_pending;
dma->device_tx_status = mpc_dma_tx_status;
dma->device_prep_dma_memcpy = mpc_dma_prep_memcpy;
+ dma->device_prep_slave_sg = mpc_dma_prep_slave_sg;
+ dma->device_control = mpc_dma_device_control;
INIT_LIST_HEAD(&dma->channels);
dma_cap_set(DMA_MEMCPY, dma->cap_mask);
+ dma_cap_set(DMA_SLAVE, dma->cap_mask);
for (i = 0; i < dma->chancnt; i++) {
mchan = &mdma->channels[i];
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v11 1/6] dma: mpc512x: reorder mpc8308 specific instructions
From: Alexander Popov @ 2014-04-15 10:54 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
In-Reply-To: <1397559250-17680-1-git-send-email-a13xp0p0v88@gmail.com>
Concentrate the specific code for MPC8308 in the 'if' branch
and handle MPC512x in the 'else' branch.
This modification only reorders instructions but doesn't change behaviour.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
Acked-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Gerhard Sittig <gsi@denx.de>
---
drivers/dma/mpc512x_dma.c | 42 +++++++++++++++++++++++++-----------------
1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 448750d..2ce248b 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -52,9 +52,17 @@
#define MPC_DMA_DESCRIPTORS 64
/* Macro definitions */
-#define MPC_DMA_CHANNELS 64
#define MPC_DMA_TCD_OFFSET 0x1000
+/*
+ * Maximum channel counts for individual hardware variants
+ * and the maximum channel count over all supported controllers,
+ * used for data structure size
+ */
+#define MPC8308_DMACHAN_MAX 16
+#define MPC512x_DMACHAN_MAX 64
+#define MPC_DMA_CHANNELS 64
+
/* Arbitration mode of group and channel */
#define MPC_DMA_DMACR_EDCG (1 << 31)
#define MPC_DMA_DMACR_ERGA (1 << 3)
@@ -710,10 +718,10 @@ static int mpc_dma_probe(struct platform_device *op)
dma = &mdma->dma;
dma->dev = dev;
- if (!mdma->is_mpc8308)
- dma->chancnt = MPC_DMA_CHANNELS;
+ if (mdma->is_mpc8308)
+ dma->chancnt = MPC8308_DMACHAN_MAX;
else
- dma->chancnt = 16; /* MPC8308 DMA has only 16 channels */
+ dma->chancnt = MPC512x_DMACHAN_MAX;
dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
dma->device_free_chan_resources = mpc_dma_free_chan_resources;
dma->device_issue_pending = mpc_dma_issue_pending;
@@ -747,7 +755,19 @@ static int mpc_dma_probe(struct platform_device *op)
* - Round-robin group arbitration,
* - Round-robin channel arbitration.
*/
- if (!mdma->is_mpc8308) {
+ if (mdma->is_mpc8308) {
+ /* MPC8308 has 16 channels and lacks some registers */
+ out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
+
+ /* enable snooping */
+ out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
+ /* Disable error interrupts */
+ out_be32(&mdma->regs->dmaeeil, 0);
+
+ /* Clear interrupts status */
+ out_be32(&mdma->regs->dmaintl, 0xFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFF);
+ } else {
out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
@@ -768,18 +788,6 @@ static int mpc_dma_probe(struct platform_device *op)
/* Route interrupts to IPIC */
out_be32(&mdma->regs->dmaihsa, 0);
out_be32(&mdma->regs->dmailsa, 0);
- } else {
- /* MPC8308 has 16 channels and lacks some registers */
- out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
-
- /* enable snooping */
- out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
- /* Disable error interrupts */
- out_be32(&mdma->regs->dmaeeil, 0);
-
- /* Clear interrupts status */
- out_be32(&mdma->regs->dmaintl, 0xFFFF);
- out_be32(&mdma->regs->dmaerrl, 0xFFFF);
}
/* Register DMA engine */
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v11 0/6] MPC512x DMA slave s/g support, OF DMA lookup
From: Alexander Popov @ 2014-04-15 10:54 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
Cc: devicetree
2013/7/14 Gerhard Sittig <gsi@denx.de>:
> this series
> - introduces slave s/g support (that's support for DMA transfers which
> involve peripherals in contrast to mem-to-mem transfers)
> - adds device tree based lookup support for DMA channels
> - combines floating patches and related feedback which already covered
> several aspects of what the suggested LPB driver needs, to demonstrate
> how integration might be done
> - carries Q&D SD card support to enable another DMA client during test,
> while this patch needs to get dropped upon pickup
Changes in v2:
> - re-order mpc8308 related code paths for improved readability, no
> change in behaviour, introduction of symbolic channel names here
> already
> - squash 'execute() start condition' and 'terminate all' into the
> introduction of 'slave s/g prep' and 'device control' support; refuse
> s/g lists with more than one item since slave support is operational
> yet proper s/g support is missing (can get addressed later)
> - always start transfers from software on MPC8308 as there are no
> external request lines for peripheral flow control
> - drop dt-bindings header file and symbolic channel names in OF nodes
Changes in v3 and v4:
Part 1/5:
- use #define instead of enum since individual channels don't require
special handling.
Part 2/5:
- add a flag "will_access_peripheral" to DMA transfer descriptor
according recommendations of Gerhard Sittig.
This flag is set in mpc_dma_prep_memcpy() and mpc_dma_prep_slave_sg()
and is evaluated in mpc_dma_execute() to choose a type of start for
the transfer.
- prevent descriptors of transfers which involve peripherals from
being chained together;
each of such transfers needs hardware initiated start.
- add locking while working with struct mpc_dma_chan
according recommendations of Lars-Peter Clausen.
- remove default nbytes value. Client kernel modules must set
src_maxburst and dst_maxburst fields of struct dma_slave_config (dmaengine.h).
Changes in v5:
Part 2/5:
- add and improve comments;
- improve the code moving transfer descriptors from 'queued' to 'active' list
in mpc_dma_execute();
- allow mpc_dma_prep_slave_sg() to run with non-empty 'active' list;
- take 'mdesc' back to 'free' list in case of error in mpc_dma_prep_slave_sg();
- improve checks of the transfer parameters;
- provide the default value for 'maxburst' in mpc_dma_device_control().
Changes in v6:
Part 2/5:
- remove doubtful comment;
- fix coding style issues;
- set default value for 'maxburst' to 1 which applies to most cases;
Part 3/5:
- use dma_get_slave_channel() instead of dma_request_channel()
in new function of_dma_xlate_by_chan_id() according recommendations of
Arnd Bergmann;
Part 4/5:
- set DMA_PRIVATE flag for MPC512x DMA controller since its driver relies on
of_dma_xlate_by_chan_id() which doesn't use dma_request_channel()
any more; (removed in v7)
- resolve little patch conflict;
Part 5/5:
- resolve little patch conflict;
Changes in v7:
Part 2:
- improve comment;
Part 4:
- split in two separate patches. Part 4/6 contains device tree
binding document and in part 5/6 MPC512x DMA controller is registered
for device tree channel lookup;
- remove setting DMA_PRIVATE flag for MPC512x DMA controller from part 5/6;
Changes in v8:
Part 2:
- improve comments;
- fix style issues;
Part 6:
- remove since it has become obsolete;
Changes in v9:
A new patch (part 3/6) is added to this series according the
feedback of Andy Shevchenko.
Part 2/6:
- keep style of the comments;
- use is_slave_direction() instead of manual checks;
- remove redundant else branches of the conditions;
- make mpc_dma_device_control() return -ENXIO for unknown command;
Part 6/6:
- change according the new part 3/6;
- fix style issues;
Changes in v10:
Part 2/6:
- don't use direction field of dma_slave_config in mpc_dma_device_control()
but store settings in mpc_dma_chan for both DMA_DEV_TO_MEM and
DMA_MEM_TO_DEV cases; then retrieve the needed values in
mpc_dma_prep_slave_sg();
- fix style issue and put 2014 instead of 2013;
Part 3/6:
- fix mpc_dma_probe() error path and mpc_dma_remove(): manually free IRQs and
dispose IRQ mappings before devm_* takes care of other resources;
Part 6/6:
- change according the new part 3/6;
- fix style issue;
Changes in v11:
Part 5/6:
- remake device tree binding document according the recommendations of
Gerhard Sittig, Mark Rutland and Arnd Bergmann;
> known issues:
> - it's yet to get confirmed whether MPC8308 can use slave support or
> whether the DMA controller's driver shall actively reject it, the
> information that's available so far suggests that peripheral transfers
> to IP bus attached I/O is useful and shall not get blocked right away
- adding support for transfers which don't increment the RAM address or
do increment the peripheral "port's" address is easy with
this implementation; but which options of the common API
should be used for specifying such transfers?
Alexander Popov (6):
dma: mpc512x: reorder mpc8308 specific instructions
dma: mpc512x: add support for peripheral transfers
dma: mpc512x: fix freeing resources in mpc_dma_probe() and
mpc_dma_remove()
dma: of: Add common xlate function for matching by channel id
dma: mpc512x: add device tree binding document
dma: mpc512x: register for device tree channel lookup
.../devicetree/bindings/dma/mpc512x-dma.txt | 51 +++
arch/powerpc/boot/dts/mpc5121.dtsi | 1 +
drivers/dma/mpc512x_dma.c | 345 ++++++++++++++++++---
drivers/dma/of-dma.c | 35 +++
include/linux/of_dma.h | 4 +
5 files changed, 398 insertions(+), 38 deletions(-)
create mode 100644 Documentation/devicetree/bindings/dma/mpc512x-dma.txt
--
1.8.4.2
^ permalink raw reply
* Re: [PATCH 1/1] powerpc: Increase COMMAND_LINE_SIZE to 2048 from 512.
From: Benjamin Herrenschmidt @ 2014-04-15 9:49 UTC (permalink / raw)
To: Joseph Salisbury; +Cc: linuxppc-dev, paulus, linux-kernel, stable, anton
In-Reply-To: <534C2FEB.2000803@canonical.com>
On Mon, 2014-04-14 at 14:58 -0400, Joseph Salisbury wrote:
>
> After further review, it appears ppc does not actually use the define
> in
> the ppc headers but uses the common generic
> default(include/uapi/asm-generic/setup.h). COMMAND_LINE_SIZE should
> probably become a kernel config option. Do folks agree that is the
> correct thing to do? If so, I can re-work the patch.
No objection on my side.
Make sure you remove any unused arch define while at it.
Cheers,
Ben.
^ permalink raw reply
* [PATCH v4] powerpc: kvm: make _PAGE_NUMA take effect
From: Liu Ping Fan @ 2014-04-15 8:33 UTC (permalink / raw)
To: linuxppc-dev, kvm-ppc
Cc: Paul Mackerras, Alexander Graf, kvm, Aneesh Kumar K.V
Numa fault is a method which help to achieve auto numa balancing.
When such a page fault takes place, the page fault handler will check
whether the page is placed correctly. If not, migration should be
involved to cut down the distance between the cpu and pages.
A pte with _PAGE_NUMA help to implement numa fault. It means not to
allow the MMU to access the page directly. So a page fault is triggered
and numa fault handler gets the opportunity to run checker.
As for the access of MMU, we need special handling for the powernv's guest.
When we mark a pte with _PAGE_NUMA, we already call mmu_notifier to
invalidate it in guest's htab, but when we tried to re-insert them,
we firstly try to map it in real-mode. Only after this fails, we fallback
to virt mode, and most of important, we run numa fault handler in virt
mode. This patch guards the way of real-mode to ensure that if a pte is
marked with _PAGE_NUMA, it will NOT be mapped in real mode, instead, it will
be mapped in virt mode and have the opportunity to be checked with placement.
Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
v4:
more detail description
---
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 1d6c56a..8fcc363 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -234,7 +234,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
pte_size = psize;
pte = lookup_linux_pte_and_update(pgdir, hva, writing,
&pte_size);
- if (pte_present(pte)) {
+ if (pte_present(pte) && !pte_numa(pte)) {
if (writing && !pte_write(pte))
/* make the actual HPTE be read-only */
ptel = hpte_make_readonly(ptel);
--
1.8.1.4
^ permalink raw reply related
* RE: [PATCH 2/2] fsl/pci: fix EP device sometimes hangup when system resume from sleep
From: Dongsheng.Wang @ 2014-04-15 8:30 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev@lists.ozlabs.org, Jason.Jin@freescale.com
In-Reply-To: <1397547799-29464-2-git-send-email-dongsheng.wang@freescale.com>
Hi all,
Please ignore this patch. :(
I will resend it. Because I found when e1000 card plug in P1020 PCIe slot 2=
, we need more delay time
to let EP device return back.
Regards,
-Dongsheng
> -----Original Message-----
> From: Dongsheng Wang [mailto:dongsheng.wang@freescale.com]
> Sent: Tuesday, April 15, 2014 3:43 PM
> To: Wood Scott-B07421
> Cc: Zang Roy-R61911; Jin Zhengxiong-R64188; linuxppc-dev@lists.ozlabs.org=
; Wang
> Dongsheng-B40534
> Subject: [PATCH 2/2] fsl/pci: fix EP device sometimes hangup when system =
resume
> from sleep
>=20
> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>=20
> Root cause is pcie power management state transition need a delay.
> The delay time define in "PCI Bus Power Management Interface Specificatio=
n".
>=20
> D0, D1 or D2 --> D3 need to delay 10ms.
> D3 --> D0 need to delay 10ms.
>=20
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
>=20
> diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.=
c
> index 4bd091a..33950ad 100644
> --- a/arch/powerpc/sysdev/fsl_pci.c
> +++ b/arch/powerpc/sysdev/fsl_pci.c
> @@ -1175,15 +1175,24 @@ static void send_pme_turnoff_message(struct
> pci_controller *hose)
> setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR);
>=20
> /* Wait trun off done */
> - for (i =3D 0; i < 150; i++) {
> + /* RC will get this detect quickly */
> + for (i =3D 0; i < 50; i++) {
> dr =3D in_be32(&pci->pex_pme_mes_dr);
> - if (dr) {
> + if (dr & ENL23_DETECT_BIT) {
> out_be32(&pci->pex_pme_mes_dr, dr);
> break;
> }
>=20
> udelay(1000);
> }
> +
> + /*
> + * "PCI Bus Power Management Interface Specification" define
> + * Minimum System Software Guaranteed Delays
> + *
> + * D0, D1 or D2 --> D3, need delay 10ms.
> + */
> + mdelay(10);
> }
>=20
> static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
> @@ -1211,9 +1220,10 @@ static void fsl_pci_syscore_do_resume(struct
> pci_controller *hose)
> setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S);
>=20
> /* Wait exit done */
> - for (i =3D 0; i < 150; i++) {
> + /* RC will get this detect quickly */
> + for (i =3D 0; i < 50; i++) {
> dr =3D in_be32(&pci->pex_pme_mes_dr);
> - if (dr) {
> + if (dr & EXL23_DETECT_BIT) {
> out_be32(&pci->pex_pme_mes_dr, dr);
> break;
> }
> @@ -1221,6 +1231,14 @@ static void fsl_pci_syscore_do_resume(struct
> pci_controller *hose)
> udelay(1000);
> }
>=20
> + /*
> + * "PCI Bus Power Management Interface Specification" define
> + * Minimum System Software Guaranteed Delays
> + *
> + * D3 hot --> D0, need delay 10ms.
> + */
> + mdelay(10);
> +
> setup_pci_atmu(hose);
> }
>=20
> diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.=
h
> index c1cec77..37fc644 100644
> --- a/arch/powerpc/sysdev/fsl_pci.h
> +++ b/arch/powerpc/sysdev/fsl_pci.h
> @@ -39,6 +39,9 @@ struct platform_device;
> #define PME_DISR_EN_ENL23D 0x00002000
> #define PME_DISR_EN_EXL23D 0x00001000
>=20
> +#define ENL23_DETECT_BIT 0x00002000
> +#define EXL23_DETECT_BIT 0x00001000
> +
> /* PCI/PCI Express outbound window reg */
> struct pci_outbound_window_regs {
> __be32 potar; /* 0x.0 - Outbound translation address register */
> --
> 1.8.5
>=20
^ permalink raw reply
* [PATCH 2/2] fsl/pci: fix EP device sometimes hangup when system resume from sleep
From: Dongsheng Wang @ 2014-04-15 7:43 UTC (permalink / raw)
To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng, jason.jin
In-Reply-To: <1397547799-29464-1-git-send-email-dongsheng.wang@freescale.com>
From: Wang Dongsheng <dongsheng.wang@freescale.com>
Root cause is pcie power management state transition need a delay.
The delay time define in "PCI Bus Power Management Interface Specification".
D0, D1 or D2 --> D3 need to delay 10ms.
D3 --> D0 need to delay 10ms.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 4bd091a..33950ad 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -1175,15 +1175,24 @@ static void send_pme_turnoff_message(struct pci_controller *hose)
setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR);
/* Wait trun off done */
- for (i = 0; i < 150; i++) {
+ /* RC will get this detect quickly */
+ for (i = 0; i < 50; i++) {
dr = in_be32(&pci->pex_pme_mes_dr);
- if (dr) {
+ if (dr & ENL23_DETECT_BIT) {
out_be32(&pci->pex_pme_mes_dr, dr);
break;
}
udelay(1000);
}
+
+ /*
+ * "PCI Bus Power Management Interface Specification" define
+ * Minimum System Software Guaranteed Delays
+ *
+ * D0, D1 or D2 --> D3, need delay 10ms.
+ */
+ mdelay(10);
}
static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
@@ -1211,9 +1220,10 @@ static void fsl_pci_syscore_do_resume(struct pci_controller *hose)
setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S);
/* Wait exit done */
- for (i = 0; i < 150; i++) {
+ /* RC will get this detect quickly */
+ for (i = 0; i < 50; i++) {
dr = in_be32(&pci->pex_pme_mes_dr);
- if (dr) {
+ if (dr & EXL23_DETECT_BIT) {
out_be32(&pci->pex_pme_mes_dr, dr);
break;
}
@@ -1221,6 +1231,14 @@ static void fsl_pci_syscore_do_resume(struct pci_controller *hose)
udelay(1000);
}
+ /*
+ * "PCI Bus Power Management Interface Specification" define
+ * Minimum System Software Guaranteed Delays
+ *
+ * D3 hot --> D0, need delay 10ms.
+ */
+ mdelay(10);
+
setup_pci_atmu(hose);
}
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index c1cec77..37fc644 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -39,6 +39,9 @@ struct platform_device;
#define PME_DISR_EN_ENL23D 0x00002000
#define PME_DISR_EN_EXL23D 0x00001000
+#define ENL23_DETECT_BIT 0x00002000
+#define EXL23_DETECT_BIT 0x00001000
+
/* PCI/PCI Express outbound window reg */
struct pci_outbound_window_regs {
__be32 potar; /* 0x.0 - Outbound translation address register */
--
1.8.5
^ permalink raw reply related
* [PATCH 1/2] fsl/pci: fix RC cannot detect PME message coming
From: Dongsheng Wang @ 2014-04-15 7:43 UTC (permalink / raw)
To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng, jason.jin
From: Wang Dongsheng <dongsheng.wang@freescale.com>
PCI controller disable PME message report feature, that shouldn't
have happened. Fix it and enable PME message report feature.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 3f415e2..4bd091a 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -1150,8 +1150,7 @@ static int fsl_pci_pme_probe(struct pci_controller *hose)
pci = hose->private_data;
/* Enable PTOD, ENL23D & EXL23D */
- out_be32(&pci->pex_pme_mes_disr, 0);
- setbits32(&pci->pex_pme_mes_disr,
+ clrbits32(&pci->pex_pme_mes_disr,
PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
out_be32(&pci->pex_pme_mes_ier, 0);
--
1.8.5
^ permalink raw reply related
* [PATCH v4] Driver support for FSL RaidEngine device.
From: xuelin.shi @ 2014-04-15 5:28 UTC (permalink / raw)
To: dan.j.williams, vinod.koul
Cc: Harninder Rai, andriy.shevchenko, Naveen Burmi, dmaengine,
Xuelin Shi, linuxppc-dev
From: Xuelin Shi <xuelin.shi@freescale.com>
The RaidEngine is a new FSL hardware used for Raid5/6 acceration.
This patch enables the RaidEngine functionality and provides
hardware offloading capability for memcpy, xor and pq computation.
It works with async_tx.
Signed-off-by: Harninder Rai <harninder.rai@freescale.com>
Signed-off-by: Naveen Burmi <naveenburmi@freescale.com>
Signed-off-by: Xuelin Shi <xuelin.shi@freescale.com>
---
changes for v4:
- use upper/lower_32_bits(...) instead of direct shift.
- change FSL_RAID dependency !ASYNC_TX_ENABLE_CHANNEL_SWITCH in Kconfig.
changes for v3:
- fix memory allocation flag GFP_xxx usage.
- add re_jr_issue_pending call in cleanup.
- remove unnecessary dma_run_dependencies(...).
- use dma_cookie_complete(...) instead of direct updating cookie.
drivers/dma/Kconfig | 11 +
drivers/dma/Makefile | 1 +
drivers/dma/fsl_raid.c | 875 +++++++++++++++++++++++++++++++++++++++++++++++++
drivers/dma/fsl_raid.h | 307 +++++++++++++++++
4 files changed, 1194 insertions(+)
create mode 100644 drivers/dma/fsl_raid.c
create mode 100644 drivers/dma/fsl_raid.h
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 605b016..b85880c 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -100,6 +100,17 @@ config FSL_DMA
EloPlus is on mpc85xx and mpc86xx and Pxxx parts, and the Elo3 is on
some Txxx and Bxxx parts.
+config FSL_RAID
+ tristate "Freescale RAID engine Support"
+ depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH
+ select DMA_ENGINE
+ select DMA_ENGINE_RAID
+ ---help---
+ Enable support for Freescale RAID Engine. RAID Engine is
+ available on some QorIQ SoCs (like P5020). It has
+ the capability to offload memcpy, xor and pq computation
+ for raid5/6.
+
config MPC512X_DMA
tristate "Freescale MPC512x built-in DMA engine support"
depends on PPC_MPC512x || PPC_MPC831x
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a029d0f4..60b163b 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
obj-$(CONFIG_TI_CPPI41) += cppi41.o
obj-$(CONFIG_K3_DMA) += k3dma.o
obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
+obj-$(CONFIG_FSL_RAID) += fsl_raid.o
diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
new file mode 100644
index 0000000..1dc5981
--- /dev/null
+++ b/drivers/dma/fsl_raid.c
@@ -0,0 +1,875 @@
+/*
+ * drivers/dma/fsl_raid.c
+ *
+ * Freescale RAID Engine device driver
+ *
+ * Author:
+ * Harninder Rai <harninder.rai@freescale.com>
+ * Naveen Burmi <naveenburmi@freescale.com>
+ *
+ * Rewrite:
+ * Xuelin Shi <xuelin.shi@freescale.com>
+ *
+ * Copyright (c) 2010-2014 Freescale Semiconductor, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Theory of operation:
+ *
+ * General capabilities:
+ * RAID Engine (RE) block is capable of offloading XOR, memcpy and P/Q
+ * calculations required in RAID5 and RAID6 operations. RE driver
+ * registers with Linux's ASYNC layer as dma driver. RE hardware
+ * maintains strict ordering of the requests through chained
+ * command queueing.
+ *
+ * Data flow:
+ * Software RAID layer of Linux (MD layer) maintains RAID partitions,
+ * strips, stripes etc. It sends requests to the underlying AYSNC layer
+ * which further passes it to RE driver. ASYNC layer decides which request
+ * goes to which job ring of RE hardware. For every request processed by
+ * RAID Engine, driver gets an interrupt unless coalescing is set. The
+ * per job ring interrupt handler checks the status register for errors,
+ * clears the interrupt and leave the post interrupt processing to the irq
+ * thread.
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/dmaengine.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#include "dmaengine.h"
+#include "fsl_raid.h"
+
+#define MAX_XOR_SRCS 16
+#define MAX_PQ_SRCS 16
+#define MAX_INITIAL_DESCS 256
+#define MAX_DESCS_LIMIT (4 * MAX_INITIAL_DESCS)
+#define FRAME_FORMAT 0x1
+#define MAX_DATA_LENGTH (1024*1024)
+
+#define to_fsl_re_dma_desc(tx) container_of(tx, \
+ struct fsl_re_dma_async_tx_desc, async_tx)
+
+/* Add descriptors into per jr software queue - submit_q */
+static dma_cookie_t re_jr_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct fsl_re_dma_async_tx_desc *desc;
+ struct re_jr *jr;
+ dma_cookie_t cookie;
+ unsigned long flags;
+
+ desc = to_fsl_re_dma_desc(tx);
+ jr = container_of(tx->chan, struct re_jr, chan);
+
+ spin_lock_irqsave(&jr->desc_lock, flags);
+ cookie = dma_cookie_assign(tx);
+ list_add_tail(&desc->node, &jr->submit_q);
+ spin_unlock_irqrestore(&jr->desc_lock, flags);
+
+ return cookie;
+}
+
+/* Copy descriptor from per jr software queue into hardware job ring */
+static void re_jr_issue_pending(struct dma_chan *chan)
+{
+ struct re_jr *jr;
+ int avail;
+ struct fsl_re_dma_async_tx_desc *desc, *_desc;
+ unsigned long flags;
+
+ jr = container_of(chan, struct re_jr, chan);
+
+ avail = RE_JR_INB_SLOT_AVAIL(in_be32(&jr->jrregs->inbring_slot_avail));
+ if (!avail)
+ return;
+
+ spin_lock_irqsave(&jr->desc_lock, flags);
+ list_for_each_entry_safe(desc, _desc, &jr->submit_q, node) {
+ if (!avail)
+ break;
+
+ list_move_tail(&desc->node, &jr->active_q);
+
+ memcpy(&jr->inb_ring_virt_addr[jr->inb_count], &desc->hwdesc,
+ sizeof(struct jr_hw_desc));
+
+ jr->inb_count = (jr->inb_count + 1) & RING_SIZE_MASK;
+
+ /* add one job into job ring */
+ out_be32(&jr->jrregs->inbring_add_job, RE_JR_INB_JOB_ADD(1));
+ avail--;
+ }
+ spin_unlock_irqrestore(&jr->desc_lock, flags);
+}
+
+static void re_jr_desc_done(struct fsl_re_dma_async_tx_desc *desc)
+{
+ dma_async_tx_callback callback;
+ void *callback_param;
+
+ dma_cookie_complete(&desc->async_tx);
+
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
+ if (callback)
+ callback(callback_param);
+
+ dma_descriptor_unmap(&desc->async_tx);
+}
+
+static void re_jr_dequeue(struct re_jr *jr)
+{
+ struct fsl_re_dma_async_tx_desc *desc, *_desc;
+ struct jr_hw_desc *hwdesc;
+ unsigned int count;
+ int found;
+
+ count = RE_JR_OUB_SLOT_FULL(in_be32(&jr->jrregs->oubring_slot_full));
+ while (count--) {
+ found = 0;
+ hwdesc = &jr->oub_ring_virt_addr[jr->oub_count];
+ list_for_each_entry_safe(desc, _desc, &jr->active_q, node) {
+ /* compare the hw dma addr to find the completed */
+ if (desc->hwdesc.lbea32 == hwdesc->lbea32 &&
+ desc->hwdesc.addr_low == hwdesc->addr_low) {
+ found = 1;
+ break;
+ }
+ }
+
+ BUG_ON(!found);
+ re_jr_desc_done(desc);
+ list_move_tail(&desc->node, &jr->ack_q);
+
+ jr->oub_count = (jr->oub_count + 1) & RING_SIZE_MASK;
+ out_be32(&jr->jrregs->oubring_job_rmvd, RE_JR_OUB_JOB_RMVD(1));
+ }
+}
+
+static void re_jr_cleanup_descs(struct re_jr *jr)
+{
+ struct fsl_re_dma_async_tx_desc *desc, *_desc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&jr->desc_lock, flags);
+ re_jr_dequeue(jr);
+ list_for_each_entry_safe(desc, _desc, &jr->ack_q, node) {
+ if (async_tx_test_ack(&desc->async_tx))
+ list_move_tail(&desc->node, &jr->free_q);
+ }
+ spin_unlock_irqrestore(&jr->desc_lock, flags);
+
+ re_jr_issue_pending(&jr->chan);
+}
+
+static irqreturn_t re_jr_isr_thread(int irq, void *data)
+{
+ struct re_jr *jr = (struct re_jr *)data;
+
+ re_jr_cleanup_descs(jr);
+
+ return IRQ_HANDLED;
+}
+
+/* Per Job Ring interrupt handler */
+static irqreturn_t re_jr_isr(int irq, void *data)
+{
+ struct re_jr *jr = (struct re_jr *)data;
+
+ u32 irqstate, status;
+ irqstate = in_be32(&jr->jrregs->jr_interrupt_status);
+ if (!irqstate)
+ return IRQ_NONE;
+
+ /*
+ * There's no way in upper layer (read MD layer) to recover from
+ * error conditions except restart everything. In long term we
+ * need to do something more than just crashing
+ */
+ if (irqstate & RE_JR_ERROR) {
+ status = in_be32(&jr->jrregs->jr_status);
+ dev_err(jr->dev, "jr error irqstate: %x, status: %x\n",
+ irqstate, status);
+ }
+
+ /* Clear interrupt */
+ out_be32(&jr->jrregs->jr_interrupt_status, RE_JR_CLEAR_INT);
+ return IRQ_WAKE_THREAD;
+}
+
+static enum dma_status re_jr_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ enum dma_status ret;
+ struct re_jr *jr = container_of(chan, struct re_jr, chan);
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+
+ if (ret != DMA_COMPLETE) {
+ re_jr_cleanup_descs(jr);
+ ret = dma_cookie_status(chan, cookie, txstate);
+ }
+
+ return ret;
+}
+
+void fill_cfd_frame(struct cmpnd_frame *cf, u8 index,
+ size_t length, dma_addr_t addr, bool final)
+{
+ u32 efrl = length & CF_LENGTH_MASK;
+ efrl |= final << CF_FINAL_SHIFT;
+ cf[index].efrl32 = efrl;
+ cf[index].addr_high = upper_32_bits(addr);
+ cf[index].addr_low = lower_32_bits(addr);
+}
+
+static struct fsl_re_dma_async_tx_desc *re_jr_init_desc(struct re_jr *jr,
+ struct fsl_re_dma_async_tx_desc *desc, void *cf, dma_addr_t paddr)
+{
+ desc->jr = jr;
+ desc->async_tx.tx_submit = re_jr_tx_submit;
+ dma_async_tx_descriptor_init(&desc->async_tx, &jr->chan);
+ INIT_LIST_HEAD(&desc->node);
+
+ desc->hwdesc.fmt32 = FRAME_FORMAT << HWDESC_FMT_SHIFT;
+ desc->hwdesc.lbea32 = upper_32_bits(paddr);
+ desc->hwdesc.addr_low = lower_32_bits(paddr);
+ desc->cf_addr = cf;
+ desc->cf_paddr = paddr;
+
+ desc->cdb_addr = (void *)(cf + RE_CF_DESC_SIZE);
+ desc->cdb_paddr = paddr + RE_CF_DESC_SIZE;
+
+ return desc;
+}
+
+static struct fsl_re_dma_async_tx_desc *re_jr_alloc_desc(struct re_jr *jr,
+ unsigned long flags)
+{
+ struct fsl_re_dma_async_tx_desc *desc = NULL;
+ void *cf;
+ dma_addr_t paddr;
+ unsigned long lock_flag;
+
+ re_jr_cleanup_descs(jr);
+
+ spin_lock_irqsave(&jr->desc_lock, lock_flag);
+ if (!list_empty(&jr->free_q)) {
+ /* take one desc from free_q */
+ desc = list_first_entry(&jr->free_q,
+ struct fsl_re_dma_async_tx_desc, node);
+ list_del(&desc->node);
+
+ desc->async_tx.flags = flags;
+ }
+ spin_unlock_irqrestore(&jr->desc_lock, lock_flag);
+
+ if (!desc) {
+ desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
+ cf = dma_pool_alloc(jr->re_dev->cf_desc_pool, GFP_NOWAIT,
+ &paddr);
+ if (!desc || !cf) {
+ kfree(desc);
+ return NULL;
+ }
+
+ desc = re_jr_init_desc(jr, desc, cf, paddr);
+ desc->async_tx.flags = flags;
+
+ spin_lock_irqsave(&jr->desc_lock, lock_flag);
+ jr->alloc_count++;
+ spin_unlock_irqrestore(&jr->desc_lock, lock_flag);
+ }
+
+ return desc;
+}
+
+static struct dma_async_tx_descriptor *re_jr_prep_genq(
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+ unsigned int src_cnt, const unsigned char *scf, size_t len,
+ unsigned long flags)
+{
+ struct re_jr *jr;
+ struct fsl_re_dma_async_tx_desc *desc;
+ struct xor_cdb *xor;
+ struct cmpnd_frame *cf;
+ u32 cdb;
+ unsigned int i, j;
+
+ if (len > MAX_DATA_LENGTH) {
+ pr_err("Length greater than %d not supported\n",
+ MAX_DATA_LENGTH);
+ return NULL;
+ }
+
+ jr = container_of(chan, struct re_jr, chan);
+ desc = re_jr_alloc_desc(jr, flags);
+ if (desc <= 0)
+ return NULL;
+
+ /* Filling xor CDB */
+ cdb = RE_XOR_OPCODE << RE_CDB_OPCODE_SHIFT;
+ cdb |= (src_cnt - 1) << RE_CDB_NRCS_SHIFT;
+ cdb |= RE_BLOCK_SIZE << RE_CDB_BLKSIZE_SHIFT;
+ cdb |= INTERRUPT_ON_ERROR << RE_CDB_ERROR_SHIFT;
+ cdb |= DATA_DEPENDENCY << RE_CDB_DEPEND_SHIFT;
+ xor = desc->cdb_addr;
+ xor->cdb32 = cdb;
+
+ if (scf != NULL) {
+ /* compute q = src0*coef0^src1*coef1^..., * is GF(8) mult */
+ for (i = 0; i < src_cnt; i++)
+ xor->gfm[i] = scf[i];
+ } else {
+ /* compute P, that is XOR all srcs */
+ for (i = 0; i < src_cnt; i++)
+ xor->gfm[i] = 1;
+ }
+
+ /* Filling frame 0 of compound frame descriptor with CDB */
+ cf = desc->cf_addr;
+ fill_cfd_frame(cf, 0, sizeof(struct xor_cdb), desc->cdb_paddr, 0);
+
+ /* Fill CFD's 1st frame with dest buffer */
+ fill_cfd_frame(cf, 1, len, dest, 0);
+
+ /* Fill CFD's rest of the frames with source buffers */
+ for (i = 2, j = 0; j < src_cnt; i++, j++)
+ fill_cfd_frame(cf, i, len, src[j], 0);
+
+ /* Setting the final bit in the last source buffer frame in CFD */
+ cf[i - 1].efrl32 |= 1 << CF_FINAL_SHIFT;
+
+ return &desc->async_tx;
+}
+
+/*
+ * Prep function for P parity calculation.In RAID Engine terminology,
+ * XOR calculation is called GenQ calculation done through GenQ command
+ */
+static struct dma_async_tx_descriptor *re_jr_prep_dma_xor(
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+ unsigned int src_cnt, size_t len, unsigned long flags)
+{
+ /* NULL let genq take all coef as 1 */
+ return re_jr_prep_genq(chan, dest, src, src_cnt, NULL, len, flags);
+}
+
+/*
+ * Prep function for P/Q parity calculation.In RAID Engine terminology,
+ * P/Q calculation is called GenQQ done through GenQQ command
+ */
+static struct dma_async_tx_descriptor *re_jr_prep_pq(
+ struct dma_chan *chan, dma_addr_t *dest, dma_addr_t *src,
+ unsigned int src_cnt, const unsigned char *scf, size_t len,
+ unsigned long flags)
+{
+ struct re_jr *jr;
+ struct fsl_re_dma_async_tx_desc *desc;
+ struct pq_cdb *pq;
+ struct cmpnd_frame *cf;
+ u32 cdb;
+ u8 *p;
+ int gfmq_len, i, j;
+
+ if (len > MAX_DATA_LENGTH) {
+ pr_err("Length greater than %d not supported\n",
+ MAX_DATA_LENGTH);
+ return NULL;
+ }
+
+ /*
+ * RE requires at least 2 sources, if given only one source, we pass the
+ * second source same as the first one.
+ * With only one source, generating P is meaningless, only generate Q.
+ */
+ if (src_cnt == 1) {
+ struct dma_async_tx_descriptor *tx;
+ dma_addr_t dma_src[2];
+ unsigned char coef[2];
+
+ dma_src[0] = *src;
+ coef[0] = *scf;
+ dma_src[1] = *src;
+ coef[1] = 0;
+ tx = re_jr_prep_genq(chan, dest[1], dma_src, 2, coef, len,
+ flags);
+ if (tx)
+ desc = to_fsl_re_dma_desc(tx);
+
+ return tx;
+ }
+
+ /*
+ * During RAID6 array creation, Linux's MD layer gets P and Q
+ * calculated separately in two steps. But our RAID Engine has
+ * the capability to calculate both P and Q with a single command
+ * Hence to merge well with MD layer, we need to provide a hook
+ * here and call re_jq_prep_genq() function
+ */
+
+ if (flags & DMA_PREP_PQ_DISABLE_P)
+ return re_jr_prep_genq(chan, dest[1], src, src_cnt,
+ scf, len, flags);
+
+ jr = container_of(chan, struct re_jr, chan);
+ desc = re_jr_alloc_desc(jr, flags);
+ if (desc <= 0)
+ return NULL;
+
+ /* Filling GenQQ CDB */
+ cdb = RE_PQ_OPCODE << RE_CDB_OPCODE_SHIFT;
+ cdb |= (src_cnt - 1) << RE_CDB_NRCS_SHIFT;
+ cdb |= RE_BLOCK_SIZE << RE_CDB_BLKSIZE_SHIFT;
+ cdb |= BUFFERABLE_OUTPUT << RE_CDB_BUFFER_SHIFT;
+ cdb |= DATA_DEPENDENCY << RE_CDB_DEPEND_SHIFT;
+
+ pq = desc->cdb_addr;
+ pq->cdb32 = cdb;
+
+ p = pq->gfm_q1;
+ /* Init gfm_q1[] */
+ for (i = 0; i < src_cnt; i++)
+ p[i] = 1;
+
+ /* Align gfm[] to 32bit */
+ gfmq_len = ALIGN(src_cnt, 4);
+
+ /* Init gfm_q2[] */
+ p += gfmq_len;
+ for (i = 0; i < src_cnt; i++)
+ p[i] = scf[i];
+
+ /* Filling frame 0 of compound frame descriptor with CDB */
+ cf = desc->cf_addr;
+ fill_cfd_frame(cf, 0, sizeof(struct pq_cdb), desc->cdb_paddr, 0);
+
+ /* Fill CFD's 1st & 2nd frame with dest buffers */
+ for (i = 1, j = 0; i < 3; i++, j++)
+ fill_cfd_frame(cf, i, len, dest[j], 0);
+
+ /* Fill CFD's rest of the frames with source buffers */
+ for (i = 3, j = 0; j < src_cnt; i++, j++)
+ fill_cfd_frame(cf, i, len, src[j], 0);
+
+ /* Setting the final bit in the last source buffer frame in CFD */
+ cf[i - 1].efrl32 |= 1 << CF_FINAL_SHIFT;
+
+ return &desc->async_tx;
+}
+
+/*
+ * Prep function for memcpy. In RAID Engine, memcpy is done through MOVE
+ * command. Logic of this function will need to be modified once multipage
+ * support is added in Linux's MD/ASYNC Layer
+ */
+static struct dma_async_tx_descriptor *re_jr_prep_memcpy(
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct re_jr *jr;
+ struct fsl_re_dma_async_tx_desc *desc;
+ size_t length;
+ struct cmpnd_frame *cf;
+ struct move_cdb *move;
+ u32 cdb;
+
+ jr = container_of(chan, struct re_jr, chan);
+
+ if (len > MAX_DATA_LENGTH) {
+ pr_err("Length greater than %d not supported\n",
+ MAX_DATA_LENGTH);
+ return NULL;
+ }
+
+ desc = re_jr_alloc_desc(jr, flags);
+ if (desc <= 0)
+ return NULL;
+
+ /* Filling move CDB */
+ cdb = RE_MOVE_OPCODE << RE_CDB_OPCODE_SHIFT;
+ cdb |= RE_BLOCK_SIZE << RE_CDB_BLKSIZE_SHIFT;
+ cdb |= INTERRUPT_ON_ERROR << RE_CDB_ERROR_SHIFT;
+ cdb |= DATA_DEPENDENCY << RE_CDB_DEPEND_SHIFT;
+
+ move = desc->cdb_addr;
+ move->cdb32 = cdb;
+
+ /* Filling frame 0 of CFD with move CDB */
+ cf = desc->cf_addr;
+ fill_cfd_frame(cf, 0, sizeof(struct move_cdb), desc->cdb_paddr, 0);
+
+ length = min_t(size_t, len, MAX_DATA_LENGTH);
+
+ /* Fill CFD's 1st frame with dest buffer */
+ fill_cfd_frame(cf, 1, length, dest, 0);
+
+ /* Fill CFD's 2nd frame with src buffer */
+ fill_cfd_frame(cf, 2, length, src, 1);
+
+ return &desc->async_tx;
+}
+
+static int re_jr_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct re_jr *jr = container_of(chan, struct re_jr, chan);
+ struct fsl_re_dma_async_tx_desc *desc;
+ void *cf;
+ dma_addr_t paddr;
+
+ int i;
+
+ for (i = 0; i < MAX_DESCS_LIMIT; i++) {
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ cf = dma_pool_alloc(jr->re_dev->cf_desc_pool, GFP_KERNEL,
+ &paddr);
+ if (!desc || !cf) {
+ kfree(desc);
+ break;
+ }
+
+ INIT_LIST_HEAD(&desc->node);
+ re_jr_init_desc(jr, desc, cf, paddr);
+
+ list_add_tail(&desc->node, &jr->free_q);
+ jr->alloc_count++;
+ }
+ return jr->alloc_count;
+}
+
+static void re_jr_free_chan_resources(struct dma_chan *chan)
+{
+ struct re_jr *jr = container_of(chan, struct re_jr, chan);
+ struct fsl_re_dma_async_tx_desc *desc;
+
+ while (jr->alloc_count--) {
+ desc = list_first_entry(&jr->free_q,
+ struct fsl_re_dma_async_tx_desc,
+ node);
+
+ list_del(&desc->node);
+ dma_pool_free(jr->re_dev->cf_desc_pool, desc->cf_addr,
+ desc->cf_paddr);
+ kfree(desc);
+ }
+
+ BUG_ON(!list_empty(&jr->free_q));
+}
+
+int re_jr_probe(struct platform_device *ofdev,
+ struct device_node *np, u8 q, u32 off)
+{
+ struct device *dev;
+ struct re_drv_private *repriv;
+ struct re_jr *jr;
+ struct dma_device *dma_dev;
+ u32 ptr;
+ u32 status;
+ int ret = 0, rc;
+ struct platform_device *jr_ofdev;
+
+ dev = &ofdev->dev;
+ repriv = dev_get_drvdata(dev);
+ dma_dev = &repriv->dma_dev;
+
+ jr = devm_kzalloc(dev, sizeof(*jr), GFP_KERNEL);
+ if (!jr) {
+ dev_err(dev, "No free memory for allocating JR struct\n");
+ return -ENOMEM;
+ }
+
+ /* create platform device for jr node */
+ jr_ofdev = of_platform_device_create(np, NULL, dev);
+ if (jr_ofdev == NULL) {
+ dev_err(dev, "Not able to create ofdev for jr %d\n", q);
+ ret = -EINVAL;
+ goto err_free;
+ }
+ dev_set_drvdata(&jr_ofdev->dev, jr);
+
+ /* read reg property from dts */
+ rc = of_property_read_u32(np, "reg", &ptr);
+ if (rc) {
+ dev_err(dev, "Reg property not found in JR number %d\n", q);
+ ret = -ENODEV;
+ goto err_free;
+ }
+
+ jr->jrregs = (struct jr_config_regs *)((u8 *)repriv->re_regs +
+ off + ptr);
+
+ /* read irq property from dts */
+ jr->irq = irq_of_parse_and_map(np, 0);
+ if (jr->irq == NO_IRQ) {
+ dev_err(dev, "No IRQ defined for JR %d\n", q);
+ ret = -ENODEV;
+ goto err_free;
+ }
+
+ ret = devm_request_threaded_irq(&jr_ofdev->dev, jr->irq, re_jr_isr,
+ re_jr_isr_thread, 0, jr->name, jr);
+
+ if (ret) {
+ dev_err(dev, "Unable to register JR interrupt for JR %d\n", q);
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ snprintf(jr->name, sizeof(jr->name), "re_jr%02d", q);
+
+ repriv->re_jrs[q] = jr;
+ jr->chan.device = dma_dev;
+ jr->chan.private = jr;
+ jr->dev = &jr_ofdev->dev;
+ jr->re_dev = repriv;
+
+ spin_lock_init(&jr->desc_lock);
+ INIT_LIST_HEAD(&jr->ack_q);
+ INIT_LIST_HEAD(&jr->active_q);
+ INIT_LIST_HEAD(&jr->submit_q);
+ INIT_LIST_HEAD(&jr->free_q);
+
+ list_add_tail(&jr->chan.device_node, &dma_dev->channels);
+ dma_dev->chancnt++;
+
+ jr->inb_ring_virt_addr = dma_pool_alloc(jr->re_dev->hw_desc_pool,
+ GFP_KERNEL, &jr->inb_phys_addr);
+
+ if (!jr->inb_ring_virt_addr) {
+ dev_err(dev, "No dma memory for inb_ring_virt_addr\n");
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ jr->oub_ring_virt_addr = dma_pool_alloc(jr->re_dev->hw_desc_pool,
+ GFP_KERNEL, &jr->oub_phys_addr);
+
+ if (!jr->oub_ring_virt_addr) {
+ dev_err(dev, "No dma memory for oub_ring_virt_addr\n");
+ ret = -ENOMEM;
+ goto err_free_1;
+ }
+
+ jr->inb_count = 0;
+ jr->oub_count = 0;
+ jr->alloc_count = 0;
+
+ /* Program the Inbound/Outbound ring base addresses and size */
+ out_be32(&jr->jrregs->inbring_base_h,
+ jr->inb_phys_addr & RE_JR_ADDRESS_BIT_MASK);
+ out_be32(&jr->jrregs->oubring_base_h,
+ jr->oub_phys_addr & RE_JR_ADDRESS_BIT_MASK);
+ out_be32(&jr->jrregs->inbring_base_l,
+ jr->inb_phys_addr >> RE_JR_ADDRESS_BIT_SHIFT);
+ out_be32(&jr->jrregs->oubring_base_l,
+ jr->oub_phys_addr >> RE_JR_ADDRESS_BIT_SHIFT);
+ out_be32(&jr->jrregs->inbring_size, RING_SIZE << RING_SIZE_SHIFT);
+ out_be32(&jr->jrregs->oubring_size, RING_SIZE << RING_SIZE_SHIFT);
+
+ /* Read LIODN value from u-boot */
+ status = in_be32(&jr->jrregs->jr_config_1) & RE_JR_REG_LIODN_MASK;
+
+ /* Program the CFG reg */
+ out_be32(&jr->jrregs->jr_config_1,
+ RE_JR_CFG1_CBSI | RE_JR_CFG1_CBS0 | status);
+
+ /* Enable RE/JR */
+ out_be32(&jr->jrregs->jr_command, RE_JR_ENABLE);
+
+ return 0;
+
+err_free_1:
+ dma_pool_free(jr->re_dev->hw_desc_pool, jr->inb_ring_virt_addr,
+ jr->inb_phys_addr);
+err_free:
+ return ret;
+}
+
+/* Probe function for RAID Engine */
+static int raide_probe(struct platform_device *ofdev)
+{
+ struct re_drv_private *repriv;
+ struct device_node *np;
+ struct device_node *child;
+ u32 off;
+ u8 ridx = 0;
+ struct dma_device *dma_dev;
+ struct resource *res;
+ int rc;
+ struct device *dev = &ofdev->dev;
+
+ dev_info(dev, "Freescale RAID Engine driver\n");
+
+ repriv = devm_kzalloc(dev, sizeof(*repriv), GFP_KERNEL);
+ if (!repriv)
+ return -ENOMEM;
+
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ /* IOMAP the entire RAID Engine region */
+ repriv->re_regs = devm_ioremap(dev, res->start, resource_size(res));
+ if (!repriv->re_regs)
+ return -EBUSY;
+
+ dev_set_drvdata(dev, repriv);
+
+ /* Print the RE version */
+ dev_info(dev, "Ver = %x\n", in_be32(&repriv->re_regs->re_version_id));
+
+ /* Program the RE mode */
+ out_be32(&repriv->re_regs->global_config, RE_NON_DPAA_MODE);
+ dev_info(dev, "RE mode is %x\n",
+ in_be32(&repriv->re_regs->global_config));
+
+ /* Program Galois Field polynomial */
+ out_be32(&repriv->re_regs->galois_field_config, RE_GFM_POLY);
+ dev_info(dev, "Galois Field Polynomial is %x\n",
+ in_be32(&repriv->re_regs->galois_field_config));
+
+ dma_dev = &repriv->dma_dev;
+ dma_dev->dev = dev;
+ INIT_LIST_HEAD(&dma_dev->channels);
+ dma_set_mask(dev, DMA_BIT_MASK(40));
+
+ dma_dev->device_alloc_chan_resources = re_jr_alloc_chan_resources;
+ dma_dev->device_tx_status = re_jr_tx_status;
+ dma_dev->device_issue_pending = re_jr_issue_pending;
+
+ dma_dev->max_xor = MAX_XOR_SRCS;
+ dma_dev->device_prep_dma_xor = re_jr_prep_dma_xor;
+ dma_cap_set(DMA_XOR, dma_dev->cap_mask);
+
+ dma_dev->max_pq = MAX_PQ_SRCS;
+ dma_dev->device_prep_dma_pq = re_jr_prep_pq;
+ dma_cap_set(DMA_PQ, dma_dev->cap_mask);
+
+ dma_dev->device_prep_dma_memcpy = re_jr_prep_memcpy;
+ dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+
+ dma_dev->device_free_chan_resources = re_jr_free_chan_resources;
+
+ repriv->total_jrs = 0;
+
+ repriv->cf_desc_pool = dmam_pool_create("re_cf_desc_pool", dev,
+ RE_CF_CDB_SIZE,
+ RE_CF_CDB_ALIGN, 0);
+
+ if (!repriv->cf_desc_pool) {
+ pr_err("No memory for dma desc pool\n");
+ return -ENOMEM;
+ }
+
+ repriv->hw_desc_pool = dmam_pool_create("re_hw_desc_pool", dev,
+ sizeof(struct jr_hw_desc) * RING_SIZE,
+ FRAME_DESC_ALIGNMENT, 0);
+ if (!repriv->hw_desc_pool) {
+ pr_err("No memory for hw desc pool\n");
+ return -ENOMEM;
+ }
+
+ /* Parse Device tree to find out the total number of JQs present */
+ for_each_compatible_node(np, NULL, "fsl,raideng-v1.0-job-queue") {
+ rc = of_property_read_u32(np, "reg", &off);
+ if (rc) {
+ dev_err(dev, "Reg property not found in JQ node\n");
+ return -ENODEV;
+ }
+ /* Find out the Job Rings present under each JQ */
+ for_each_child_of_node(np, child) {
+ rc = of_device_is_compatible(child,
+ "fsl,raideng-v1.0-job-ring");
+ if (rc) {
+ re_jr_probe(ofdev, child, ridx++, off);
+ repriv->total_jrs++;
+ }
+ }
+ }
+
+ dma_async_device_register(dma_dev);
+
+ return 0;
+}
+
+static void release_jr(struct re_jr *jr)
+{
+ dma_pool_free(jr->re_dev->hw_desc_pool, jr->inb_ring_virt_addr,
+ jr->inb_phys_addr);
+
+ dma_pool_free(jr->re_dev->hw_desc_pool, jr->oub_ring_virt_addr,
+ jr->oub_phys_addr);
+}
+
+static int raide_remove(struct platform_device *ofdev)
+{
+ struct re_drv_private *repriv;
+ struct device *dev;
+ int i;
+
+ dev = &ofdev->dev;
+ repriv = dev_get_drvdata(dev);
+
+ /* Cleanup JR related memory areas */
+ for (i = 0; i < repriv->total_jrs; i++)
+ release_jr(repriv->re_jrs[i]);
+
+ /* Unregister the driver */
+ dma_async_device_unregister(&repriv->dma_dev);
+
+ return 0;
+}
+
+static struct of_device_id raide_ids[] = {
+ { .compatible = "fsl,raideng-v1.0", },
+ {}
+};
+
+static struct platform_driver raide_driver = {
+ .driver = {
+ .name = "fsl-raideng",
+ .owner = THIS_MODULE,
+ .of_match_table = raide_ids,
+ },
+ .probe = raide_probe,
+ .remove = raide_remove,
+};
+
+module_platform_driver(raide_driver);
+
+MODULE_AUTHOR("Harninder Rai <harninder.rai@freescale.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Freescale RAID Engine Device Driver");
diff --git a/drivers/dma/fsl_raid.h b/drivers/dma/fsl_raid.h
new file mode 100644
index 0000000..225dbf2
--- /dev/null
+++ b/drivers/dma/fsl_raid.h
@@ -0,0 +1,307 @@
+/*
+ * drivers/dma/fsl_raid.h
+ *
+ * Freescale RAID Engine device driver
+ *
+ * Author:
+ * Harninder Rai <harninder.rai@freescale.com>
+ * Naveen Burmi <naveenburmi@freescale.com>
+ *
+ * Rewrite:
+ * Xuelin Shi <xuelin.shi@freescale.com>
+
+ * Copyright (c) 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define MAX_RE_JRS 4
+
+#define RE_DPAA_MODE (1 << 30)
+#define RE_NON_DPAA_MODE (1 << 31)
+#define RE_GFM_POLY 0x1d000000
+#define RE_JR_INB_JOB_ADD(x) ((x) << 16)
+#define RE_JR_OUB_JOB_RMVD(x) ((x) << 16)
+#define RE_JR_CFG1_CBSI 0x08000000
+#define RE_JR_CFG1_CBS0 0x00080000
+#define RE_JR_OUB_SLOT_FULL_SHIFT 8
+#define RE_JR_OUB_SLOT_FULL(x) ((x) >> RE_JR_OUB_SLOT_FULL_SHIFT)
+#define RE_JR_INB_SLOT_AVAIL_SHIFT 8
+#define RE_JR_INB_SLOT_AVAIL(x) ((x) >> RE_JR_INB_SLOT_AVAIL_SHIFT)
+#define RE_PQ_OPCODE 0x1B
+#define RE_XOR_OPCODE 0x1A
+#define RE_MOVE_OPCODE 0x8
+#define FRAME_DESC_ALIGNMENT 16
+#define RE_BLOCK_SIZE 0x3 /* 4096 bytes */
+#define CACHEABLE_INPUT_OUTPUT 0x0
+#define BUFFERABLE_OUTPUT 0x0
+#define INTERRUPT_ON_ERROR 0x1
+#define DATA_DEPENDENCY 0x1
+#define ENABLE_DPI 0x0
+#define RING_SIZE 0x400
+#define RING_SIZE_MASK (RING_SIZE - 1)
+#define RING_SIZE_SHIFT 8
+#define RE_JR_ADDRESS_BIT_SHIFT 4
+#define RE_JR_ADDRESS_BIT_MASK ((1 << RE_JR_ADDRESS_BIT_SHIFT) - 1)
+#define RE_JR_ERROR 0x40000000
+#define RE_JR_INTERRUPT 0x80000000
+#define RE_JR_CLEAR_INT 0x80000000
+#define RE_JR_PAUSE 0x80000000
+#define RE_JR_ENABLE 0x80000000
+
+#define RE_JR_REG_LIODN_MASK 0x00000FFF
+#define RE_CF_CDB_ALIGN 64
+
+#define RE_CDB_OPCODE_MASK 0xF8000000
+#define RE_CDB_OPCODE_SHIFT 27
+#define RE_CDB_EXCLEN_MASK 0x03000000
+#define RE_CDB_EXCLEN_SHIFT 24
+#define RE_CDB_EXCLQ1_MASK 0x00F00000
+#define RE_CDB_EXCLQ1_SHIFT 20
+#define RE_CDB_EXCLQ2_MASK 0x000F0000
+#define RE_CDB_EXCLQ2_SHIFT 16
+#define RE_CDB_BLKSIZE_MASK 0x0000C000
+#define RE_CDB_BLKSIZE_SHIFT 14
+#define RE_CDB_CACHE_MASK 0x00003000
+#define RE_CDB_CACHE_SHIFT 12
+#define RE_CDB_BUFFER_MASK 0x00000800
+#define RE_CDB_BUFFER_SHIFT 11
+#define RE_CDB_ERROR_MASK 0x00000400
+#define RE_CDB_ERROR_SHIFT 10
+#define RE_CDB_NRCS_MASK 0x0000003C
+#define RE_CDB_NRCS_SHIFT 6
+#define RE_CDB_DEPEND_MASK 0x00000008
+#define RE_CDB_DEPEND_SHIFT 3
+#define RE_CDB_DPI_MASK 0x00000004
+#define RE_CDB_DPI_SHIFT 2
+
+/*
+ * the largest cf block is 19*sizeof(struct cmpnd_frame), which is 304 bytes.
+ * here 19 = 1(cdb)+2(dest)+16(src), align to 64bytes, that is 320 bytes.
+ * the largest cdb block: struct pq_cdb which is 180 bytes, adding to cf block
+ * 320+180=500, align to 64bytes, that is 512 bytes.
+ */
+#define RE_CF_DESC_SIZE 320
+#define RE_CF_CDB_SIZE 512
+
+struct re_ctrl {
+ /* General Configuration Registers */
+ __be32 global_config; /* Global Configuration Register */
+ u8 rsvd1[4];
+ __be32 galois_field_config; /* Galois Field Configuration Register */
+ u8 rsvd2[4];
+ __be32 jq_wrr_config; /* WRR Configuration register */
+ u8 rsvd3[4];
+ __be32 crc_config; /* CRC Configuration register */
+ u8 rsvd4[228];
+ __be32 system_reset; /* System Reset Register */
+ u8 rsvd5[252];
+ __be32 global_status; /* Global Status Register */
+ u8 rsvd6[832];
+ __be32 re_liodn_base; /* LIODN Base Register */
+ u8 rsvd7[1712];
+ __be32 re_version_id; /* Version ID register of RE */
+ __be32 re_version_id_2; /* Version ID 2 register of RE */
+ u8 rsvd8[512];
+ __be32 host_config; /* Host I/F Configuration Register */
+};
+
+struct jr_config_regs {
+ /* Registers for JR interface */
+ __be32 jr_config_0; /* Job Queue Configuration 0 Register */
+ __be32 jr_config_1; /* Job Queue Configuration 1 Register */
+ __be32 jr_interrupt_status; /* Job Queue Interrupt Status Register */
+ u8 rsvd1[4];
+ __be32 jr_command; /* Job Queue Command Register */
+ u8 rsvd2[4];
+ __be32 jr_status; /* Job Queue Status Register */
+ u8 rsvd3[228];
+
+ /* Input Ring */
+ __be32 inbring_base_h; /* Inbound Ring Base Address Register - High */
+ __be32 inbring_base_l; /* Inbound Ring Base Address Register - Low */
+ __be32 inbring_size; /* Inbound Ring Size Register */
+ u8 rsvd4[4];
+ __be32 inbring_slot_avail; /* Inbound Ring Slot Available Register */
+ u8 rsvd5[4];
+ __be32 inbring_add_job; /* Inbound Ring Add Job Register */
+ u8 rsvd6[4];
+ __be32 inbring_cnsmr_indx; /* Inbound Ring Consumer Index Register */
+ u8 rsvd7[220];
+
+ /* Output Ring */
+ __be32 oubring_base_h; /* Outbound Ring Base Address Register - High */
+ __be32 oubring_base_l; /* Outbound Ring Base Address Register - Low */
+ __be32 oubring_size; /* Outbound Ring Size Register */
+ u8 rsvd8[4];
+ __be32 oubring_job_rmvd; /* Outbound Ring Job Removed Register */
+ u8 rsvd9[4];
+ __be32 oubring_slot_full; /* Outbound Ring Slot Full Register */
+ u8 rsvd10[4];
+ __be32 oubring_prdcr_indx; /* Outbound Ring Producer Index */
+};
+
+/*
+ * Command Descriptor Block (CDB) for unicast move command.
+ * In RAID Engine terms, memcpy is done through move command
+ */
+struct move_cdb {
+ __be32 cdb32;
+};
+
+/* Data protection/integrity related fields */
+#define DPI_APPS_MASK 0xC0000000
+#define DPI_APPS_SHIFT 30
+#define DPI_REF_MASK 0x30000000
+#define DPI_REF_SHIFT 28
+#define DPI_GUARD_MASK 0x0C000000
+#define DPI_GUARD_SHIFT 26
+#define DPI_ATTR_MASK 0x03000000
+#define DPI_ATTR_SHIFT 24
+#define DPI_META_MASK 0x0000FFFF
+
+struct dpi_related {
+ __be32 dpi32;
+ __be32 ref;
+};
+
+/*
+ * CDB for GenQ command. In RAID Engine terminology, XOR is
+ * done through this command
+ */
+struct xor_cdb {
+ __be32 cdb32;
+ u8 gfm[16];
+ struct dpi_related dpi_dest_spec;
+ struct dpi_related dpi_src_spec[16];
+};
+
+/* CDB for no-op command */
+struct noop_cdb {
+ __be32 cdb32;
+};
+
+/*
+ * CDB for GenQQ command. In RAID Engine terminology, P/Q is
+ * done through this command
+ */
+struct pq_cdb {
+ __be32 cdb32;
+ u8 gfm_q1[16];
+ u8 gfm_q2[16];
+ struct dpi_related dpi_dest_spec[2];
+ struct dpi_related dpi_src_spec[16];
+};
+
+/* Compound frame */
+#define CF_ADDR_HIGH_MASK 0x000000FF
+#define CF_EXT_MASK 0x80000000
+#define CF_EXT_SHIFT 31
+#define CF_FINAL_MASK 0x40000000
+#define CF_FINAL_SHIFT 30
+#define CF_LENGTH_MASK 0x000FFFFF
+#define CF_BPID_MASK 0x00FF0000
+#define CF_BPID_SHIFT 16
+#define CF_OFFSET_MASK 0x00001FFF
+
+struct cmpnd_frame {
+ __be32 addr_high;
+ __be32 addr_low;
+ __be32 efrl32;
+ __be32 rbro32;
+};
+
+/* Frame descriptor */
+#define HWDESC_LIODN_MASK 0x3F000000
+#define HWDESC_LIODN_SHIFT 24
+#define HWDESC_BPID_MASK 0x00FF0000
+#define HWDESC_BPID_SHIFT 16
+#define HWDESC_ELIODN_MASK 0x0000F000
+#define HWDESC_ELIODN_SHIFT 12
+#define HWDESC_FMT_SHIFT 29
+#define HWDESC_FMT_MASK (0x3 << HWDESC_FMT_SHIFT)
+
+struct jr_hw_desc {
+ __be32 lbea32;
+ __be32 addr_low;
+ __be32 fmt32;
+ __be32 status;
+};
+
+/* Raid Engine device private data */
+struct re_drv_private {
+ u8 total_jrs;
+ struct dma_device dma_dev;
+ struct re_ctrl *re_regs;
+ struct re_jr *re_jrs[MAX_RE_JRS];
+ struct dma_pool *cf_desc_pool;
+ struct dma_pool *hw_desc_pool;
+};
+
+/* Per job ring data structure */
+struct re_jr {
+ char name[16];
+ spinlock_t desc_lock; /* queue lock */
+ struct list_head ack_q; /* wait to acked queue */
+ struct list_head active_q; /* already issued on hw, not completed */
+ struct list_head submit_q;
+ struct list_head free_q; /* alloc available queue */
+ struct device *dev;
+ struct re_drv_private *re_dev;
+ struct dma_chan chan;
+ struct jr_config_regs *jrregs;
+ int irq;
+ u32 alloc_count;
+
+ /* hw descriptor ring for inbound queue*/
+ dma_addr_t inb_phys_addr;
+ struct jr_hw_desc *inb_ring_virt_addr;
+ u32 inb_count;
+
+ /* hw descriptor ring for outbound queue */
+ dma_addr_t oub_phys_addr;
+ struct jr_hw_desc *oub_ring_virt_addr;
+ u32 oub_count;
+};
+
+/* Async transaction descriptor */
+struct fsl_re_dma_async_tx_desc {
+ struct dma_async_tx_descriptor async_tx;
+ struct list_head node;
+ struct jr_hw_desc hwdesc;
+ struct re_jr *jr;
+
+ /* hwdesc will point to cf_addr */
+ void *cf_addr;
+ dma_addr_t cf_paddr;
+
+ void *cdb_addr;
+ dma_addr_t cdb_paddr;
+ int status;
+};
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 1/2] fsl/corenet_generic: add a particular initialization for platform
From: Dongsheng Wang @ 2014-04-15 5:53 UTC (permalink / raw)
To: scottwood; +Cc: linuxppc-dev, haokexin, prabhakar, jason.jin, Wang Dongsheng
From: Wang Dongsheng <dongsheng.wang@freescale.com>
Corenet_generic is a generic platform initialization. Those based on
the corenet_generic board maybe need a particular initialize to
enable/set some IP-Blocks. So add "Fix Generic Initialization" to solve
this kind of special cases.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
---
*v2*
1/ Split DIU code.
2/ make fix.c as a independent driver.
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index c17aae8..fce2341 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -269,6 +269,17 @@ config CORENET_GENERIC
The following boards are supported for both 32bit and 64bit kernel:
P5020 DS and P5040 DS
+config FIX_GENERIC_PLATFORM_INIT
+ bool "Fix Generic Initialization"
+ depends on CORENET_GENERIC
+ default y
+ help
+ This option will create a initialization that is a append initialization
+ for a particular platfrom. And this particular platform also based on
+ "Freescale CoreNet Generic".
+
+ e.g. DIU need a special initialization at T104x platform.
+
endif # FSL_SOC_BOOKE
config TQM85xx
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 25cebe7..1162ac7 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_P1022_RDK) += p1022_rdk.o
obj-$(CONFIG_P1023_RDS) += p1023_rds.o
obj-$(CONFIG_TWR_P102x) += twr_p102x.o
obj-$(CONFIG_CORENET_GENERIC) += corenet_generic.o
+obj-$(CONFIG_FIX_GENERIC_PLATFORM_INIT) += fix/
obj-$(CONFIG_STX_GP3) += stx_gp3.o
obj-$(CONFIG_TQM85xx) += tqm85xx.o
obj-$(CONFIG_SBC8548) += sbc8548.o
diff --git a/arch/powerpc/platforms/85xx/fix/Makefile b/arch/powerpc/platforms/85xx/fix/Makefile
new file mode 100644
index 0000000..a8e8154
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/fix/Makefile
@@ -0,0 +1 @@
+obj-y += fix.o
diff --git a/arch/powerpc/platforms/85xx/fix/fix.c b/arch/powerpc/platforms/85xx/fix/fix.c
new file mode 100644
index 0000000..7b59a52
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/fix/fix.c
@@ -0,0 +1,26 @@
+/*
+ * Fix Different Boards Particular Initialization
+ *
+ * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/mpc85xx.h>
+#include <asm/reg.h>
+#include <asm/reg_booke.h>
+
+#include "fix.h"
+
+static int fix_platform_init(void)
+{
+ return 0;
+}
+early_initcall(fix_platform_init);
diff --git a/arch/powerpc/platforms/85xx/fix/fix.h b/arch/powerpc/platforms/85xx/fix/fix.h
new file mode 100644
index 0000000..5a8c80e3
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/fix/fix.h
@@ -0,0 +1,4 @@
+#ifndef __CORENET_GENERIC_FIX_H__
+#define __CORENET_GENERIC_FIX_H__
+
+#endif
--
1.8.5
^ permalink raw reply related
* [PATCH v2 2/2] fsl/corenet_generic: add t104x platform diu special initialization
From: Dongsheng Wang @ 2014-04-15 5:53 UTC (permalink / raw)
To: scottwood; +Cc: linuxppc-dev, haokexin, prabhakar, jason.jin, Wang Dongsheng
In-Reply-To: <1397541229-34383-1-git-send-email-dongsheng.wang@freescale.com>
From: Wang Dongsheng <dongsheng.wang@freescale.com>
T104x Platforms based on corenet_generic. The platforms DIU-block
that need a special initialization to solve some callback functions,
those functions depend on platform handle.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
---
This patch is *depends on* Prabhakar Kushwaha support T104x patchset.
v2: No change.
diff --git a/arch/powerpc/platforms/85xx/fix/Makefile b/arch/powerpc/platforms/85xx/fix/Makefile
index a8e8154..0530acd 100644
--- a/arch/powerpc/platforms/85xx/fix/Makefile
+++ b/arch/powerpc/platforms/85xx/fix/Makefile
@@ -1 +1,3 @@
obj-y += fix.o
+
+obj-y += t104x_diu.o
diff --git a/arch/powerpc/platforms/85xx/fix/fix.c b/arch/powerpc/platforms/85xx/fix/fix.c
index 7b59a52..c278eb1 100644
--- a/arch/powerpc/platforms/85xx/fix/fix.c
+++ b/arch/powerpc/platforms/85xx/fix/fix.c
@@ -21,6 +21,19 @@
static int fix_platform_init(void)
{
+ u32 svr;
+
+ svr = SVR_SOC_VER(mfspr(SPRN_SVR));
+
+ switch (svr) {
+ case SVR_T1040:
+ case SVR_T1042:
+ fix_t104x_diu_init();
+ break;
+ default:
+ pr_info("Platform is not need to fix anything\n");
+ }
+
return 0;
}
early_initcall(fix_platform_init);
diff --git a/arch/powerpc/platforms/85xx/fix/fix.h b/arch/powerpc/platforms/85xx/fix/fix.h
index 5a8c80e3..d27635f 100644
--- a/arch/powerpc/platforms/85xx/fix/fix.h
+++ b/arch/powerpc/platforms/85xx/fix/fix.h
@@ -1,4 +1,6 @@
#ifndef __CORENET_GENERIC_FIX_H__
#define __CORENET_GENERIC_FIX_H__
+extern void fix_t104x_diu_init(void);
+
#endif
diff --git a/arch/powerpc/platforms/85xx/fix/t104x_diu.c b/arch/powerpc/platforms/85xx/fix/t104x_diu.c
new file mode 100644
index 0000000..39c7242
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/fix/t104x_diu.c
@@ -0,0 +1,155 @@
+/*
+ * T104x RDB Particular Setup
+ * Should apply for RDB platform of T1040 and it's personalities.
+ * viz T1040/T1042
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/io.h>
+#include <sysdev/fsl_soc.h>
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+/*DIU Pixel ClockCR offset in scfg*/
+#define CCSR_SCFG_PIXCLKCR 0x28
+
+/* DIU Pixel Clock bits of the PIXCLKCR */
+#define PIXCLKCR_PXCKEN 0x80000000
+#define PIXCLKCR_PXCKINV 0x40000000
+#define PIXCLKCR_PXCKDLY 0x0000FF00
+#define PIXCLKCR_PXCLK_MASK 0x00FF0000
+
+/* Some CPLD register definitions */
+#define CPLD_DIUCSR 0x16
+#define CPLD_DIUCSR_DVIEN 0x80
+#define CPLD_DIUCSR_BACKLIGHT 0x0f
+
+/**
+ * t104xrdb_set_monitor_port: switch the output to a different monitor port
+ */
+static void t104xrdb_set_monitor_port(enum fsl_diu_monitor_port port)
+{
+ struct device_node *cpld_node;
+ static void __iomem *cpld_base;
+
+ cpld_node = of_find_compatible_node(NULL, NULL, "fsl,t104xrdb-cpld");
+ if (!cpld_node) {
+ pr_err("T104xRDB: missing CPLD node\n");
+ return;
+ }
+
+ cpld_base = of_iomap(cpld_node, 0);
+ if (!cpld_base) {
+ pr_err("T104xRDB: could not map cpld registers\n");
+ goto exit;
+ }
+
+ switch (port) {
+ case FSL_DIU_PORT_DVI:
+ /* Enable the DVI(HDMI) port, disable the DFP and
+ * the backlight
+ */
+ clrbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_DVIEN);
+ break;
+ case FSL_DIU_PORT_LVDS:
+ /*
+ * LVDS also needs backlight enabled, otherwise the display
+ * will be blank.
+ */
+ /* Enable the DFP port, disable the DVI*/
+ setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 8);
+ setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 4);
+ setbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_BACKLIGHT);
+ break;
+ default:
+ pr_err("T104xRDB: unsupported monitor port %i\n", port);
+ }
+
+exit:
+ of_node_put(cpld_node);
+}
+
+/**
+ * t104xrdb_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+static void t104xrdb_set_pixel_clock(unsigned int pixclock)
+{
+ struct device_node *scfg_np = NULL;
+ void __iomem *scfg;
+ unsigned long freq;
+ u64 temp;
+ u32 pxclk;
+
+ /* Map the global utilities registers. */
+ scfg_np = of_find_compatible_node(NULL, NULL, "fsl,t1040-scfg");
+ if (!scfg_np) {
+ freq = temp;
+ pr_err("T104xRDB: missing supplemental configuration unit device node\n");
+ return;
+ }
+
+ scfg = of_iomap(scfg_np, 0);
+ of_node_put(scfg_np);
+ if (!scfg) {
+ pr_err("T104xRDB: could not map device\n");
+ return;
+ }
+
+ /* Convert pixclock from a wavelength to a frequency */
+ temp = 1000000000000ULL;
+ do_div(temp, pixclock);
+ freq = temp;
+
+ /*
+ * 'pxclk' is the ratio of the platform clock to the pixel clock.
+ * This number is programmed into the PIXCLKCR register, and the valid
+ * range of values is 2-255.
+ */
+ pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+ pxclk = clamp_t(u32, pxclk, 2, 255);
+
+ /* Disable the pixel clock, and set it to non-inverted and no delay */
+ clrbits32(scfg + CCSR_SCFG_PIXCLKCR,
+ PIXCLKCR_PXCKEN | PIXCLKCR_PXCKDLY | PIXCLKCR_PXCLK_MASK);
+
+ /* Enable the clock and set the pxclk */
+ setbits32(scfg + CCSR_SCFG_PIXCLKCR, PIXCLKCR_PXCKEN | (pxclk << 16));
+
+ iounmap(scfg);
+}
+
+/**
+ * t104xrdb_valid_monitor_port: set the monitor port for sysfs
+ */
+static enum fsl_diu_monitor_port
+t104xrdb_valid_monitor_port(enum fsl_diu_monitor_port port)
+{
+ switch (port) {
+ case FSL_DIU_PORT_DVI:
+ case FSL_DIU_PORT_LVDS:
+ return port;
+ default:
+ return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */
+ }
+}
+#endif
+
+void fix_t104x_diu_init(void)
+{
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+ diu_ops.set_monitor_port = t104xrdb_set_monitor_port;
+ diu_ops.set_pixel_clock = t104xrdb_set_pixel_clock;
+ diu_ops.valid_monitor_port = t104xrdb_valid_monitor_port;
+#endif
+}
--
1.8.5
^ permalink raw reply related
* RE: [PATCH 2/2] fsl/mpic_timer: make mpic_timer to support deep sleep feature
From: Dongsheng.Wang @ 2014-04-15 3:23 UTC (permalink / raw)
To: Scott Wood
Cc: linuxppc-dev@lists.ozlabs.org, chenhui.zhao@freescale.com,
Jason.Jin@freescale.com
In-Reply-To: <1397518552.20280.235.camel@snotra.buserror.net>
DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogV29vZCBTY290dC1CMDc0
MjENCj4gU2VudDogVHVlc2RheSwgQXByaWwgMTUsIDIwMTQgNzozNiBBTQ0KPiBUbzogV2FuZyBE
b25nc2hlbmctQjQwNTM0DQo+IENjOiBKaW4gWmhlbmd4aW9uZy1SNjQxODg7IExpIFlhbmctTGVv
LVI1ODQ3MjsgWmhhbyBDaGVuaHVpLUIzNTMzNjsgbGludXhwcGMtDQo+IGRldkBsaXN0cy5vemxh
YnMub3JnDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggMi8yXSBmc2wvbXBpY190aW1lcjogbWFrZSBt
cGljX3RpbWVyIHRvIHN1cHBvcnQgZGVlcCBzbGVlcA0KPiBmZWF0dXJlDQo+IA0KPiBPbiBNb24s
IDIwMTQtMDQtMTQgYXQgMTA6MjQgKzA4MDAsIERvbmdzaGVuZyBXYW5nIHdyb3RlOg0KPiA+IEZy
b206IFdhbmcgRG9uZ3NoZW5nIDxkb25nc2hlbmcud2FuZ0BmcmVlc2NhbGUuY29tPg0KPiA+DQo+
ID4gQXQgVDEwNHggcGxhdGZyb20gdGhlIHRpbWVyIGNsb2NrIHdpbGwgYmUgY2hhbmdlZCB3aGVu
IHN5c3RlbSBnb2luZyB0bw0KPiA+IGRlZXAgc2xlZXAuDQo+IA0KPiBDb3VsZCB5b3UgZWxhYm9y
YXRlIG9uIHdoYXQgaXMgY2hhbmdpbmcgYW5kIHdoeT8NCj4gDQoNCk9rYXkuDQoNCj4gPiArI2lu
Y2x1ZGUgPGFzbS9tcGM4NXh4Lmg+DQo+ID4gICNpbmNsdWRlIDxhc20vbXBpY190aW1lci5oPg0K
PiANCj4gU28gbXVjaCBmb3IsICJUaGUgZHJpdmVyIGN1cnJlbnRseSBpcyBvbmx5IHRlc3RlZCBv
biBmc2wgY2hpcCwgYnV0IGl0IGNhbg0KPiBwb3RlbnRpYWxseSBzdXBwb3J0IG90aGVyIGdsb2Jh
bCB0aW1lcnMgY29tcGx5aW5nIHRvIE9wZW5QSUMgc3RhbmRhcmQuIg0KPiANCj4gPiAgI2RlZmlu
ZSBGU0xfR0xPQkFMX1RJTUVSCQkweDENCj4gPiBAQCAtNzEsOCArNzQsMTAgQEAgc3RydWN0IHRp
bWVyX2dyb3VwX3ByaXYgew0KPiA+ICAJc3RydWN0IHRpbWVyX3JlZ3MgX19pb21lbQkqcmVnczsN
Cj4gPiAgCXN0cnVjdCBtcGljX3RpbWVyCQl0aW1lcltUSU1FUlNfUEVSX0dST1VQXTsNCj4gPiAg
CXN0cnVjdCBsaXN0X2hlYWQJCW5vZGU7DQo+ID4gKwl1bnNpZ25lZCBsb25nCQkJaWRsZTsNCj4g
PiAgCXVuc2lnbmVkIGludAkJCXRpbWVyZnJlcTsNCj4gPiAtCXVuc2lnbmVkIGludAkJCWlkbGU7
DQo+IA0KPiBXaHk/DQo+IA0KDQpVbS4uLiBJdCBzaG91bGRuJ3QgYmUgaGFwcGVuZWQuLi5pIHdp
bGwgcmVtb3ZlIHRoaXMuDQoNCj4gPiArCXVuc2lnbmVkIGludAkJCXN1c3BlbmRlZF90aW1lcmZy
ZXE7DQo+ID4gKwl1bnNpZ25lZCBpbnQJCQlyZXN1bWVfdGltZXJmcmVxOw0KPiA+ICAJdW5zaWdu
ZWQgaW50CQkJZmxhZ3M7DQo+ID4gIAlzcGlubG9ja190CQkJbG9jazsNCj4gPiAgCXZvaWQgX19p
b21lbQkJCSpncm91cF90Y3I7DQo+ID4gQEAgLTg4LDYgKzkzLDcgQEAgc3RhdGljIHN0cnVjdCBj
YXNjYWRlX3ByaXYgY2FzY2FkZV90aW1lcltdID0geyAgfTsNCj4gPg0KPiA+ICBzdGF0aWMgTElT
VF9IRUFEKHRpbWVyX2dyb3VwX2xpc3QpOw0KPiA+ICtzdGF0aWMgaW50IHN3aXRjaF9mcmVxX2Zs
YWc7DQo+IA0KPiBOZWVkcyBkb2N1bWVudGF0aW9uLCBhbmQgYmFzZWQgb24gIl9mbGFnIiBpdCBz
aG91bGQgcHJvYmFibHkgYmUgYSBib29sLg0KPiANCg0KT2theS4NCg0KPiA+ICBzdGF0aWMgdm9p
ZCBjb252ZXJ0X3RpY2tzX3RvX3RpbWUoc3RydWN0IHRpbWVyX2dyb3VwX3ByaXYgKnByaXYsDQo+
ID4gIAkJY29uc3QgdTY0IHRpY2tzLCBzdHJ1Y3QgdGltZXZhbCAqdGltZSkgQEAgLTQyMyw2ICs0
MjksMzMgQEAgc3RydWN0DQo+ID4gbXBpY190aW1lciAqbXBpY19yZXF1ZXN0X3RpbWVyKGlycV9o
YW5kbGVyX3QgZm4sIHZvaWQgKmRldiwgIH0NCj4gPiBFWFBPUlRfU1lNQk9MKG1waWNfcmVxdWVz
dF90aW1lcik7DQo+ID4NCj4gPiArc3RhdGljIHZvaWQgdGltZXJfZ3JvdXBfZ2V0X3N1c3BlbmRl
ZF9mcmVxKHN0cnVjdCB0aW1lcl9ncm91cF9wcml2DQo+ID4gKypwcml2KSB7DQo+ID4gKwlzdHJ1
Y3QgZGV2aWNlX25vZGUgKm5wOw0KPiA+ICsNCj4gPiArCW5wID0gb2ZfZmluZF9jb21wYXRpYmxl
X25vZGUoTlVMTCwgTlVMTCwgImZzbCxxb3JpcS1jbG9ja2dlbi0yLjAiKTsNCj4gPiArCWlmICgh
bnApIHsNCj4gPiArCQlwcl9lcnIoIm1waWMgdGltZXI6IE1pc3NpbmcgY2xvY2tnZW4gZGV2aWNl
IG5vZGUuXG4iKTsNCj4gDQo+IFdoeSBpcyBpdCBhbiBlcnJvciB0byBub3QgaGF2ZSBhIDIuMCBR
b3JJUSBjbG9ja2dlbj8NCj4gDQoNClRoaXMgd2lsbCBhZmZlY3QgdGhlIGFjY3VyYWN5IG9mIHRo
ZSB0aW1lci4gQnV0IG5vdCBtZWFucyB0aGUgdGltZXIgY2Fubm90IHdvcmsuDQpNYXliZSB5b3Ug
YXJlIHJpZ2h0LCB0aGlzIHByX2VyciBzaG91bGQgYmUgYSBwcl93YXJuLg0KDQo+ID4gKwkJcmV0
dXJuOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCW9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAiY2xv
Y2stZnJlcXVlbmN5IiwgJnByaXYtPnN1c3BlbmRlZF90aW1lcmZyZXEpOw0KPiA+ICsJb2Zfbm9k
ZV9wdXQobnApOw0KPiANCj4gU2hvdWxkbid0IHRoaXMgZ28gdGhyb3VnaCB0aGUgY2xvY2sgQVBJ
Pw0KPiANCg0KU29ycnksIEknbSBub3QgY2xlYXIgYWJvdXQgY2xvY2sgQVBJLCB5b3UgbWVhbiBm
c2xfZ2V0X3N5c19mcmVxKCk/IE9yID8NCg0KVGhlIHRpbWVyIG9wZXJhdGVzIG9uIHN5c19yZWZf
Y2xrIGZyZXF1ZW5jeSBkdXJpbmcgZGVlcCBzbGVlcC4gQW5kIFRoZSB0aW1lciBydW5zIG9uDQpw
bGF0Zm9ybSBjbG9jay8yIGR1cmluZyBub3JtYWwgb3BlcmF0aW9uLg0KDQpmc2xfZ2V0X3N5c19m
cmVxKCkgY2FuIGdldCBwbGF0Zm9ybSBjbG9jaywgYnV0IGNhbm5vdCBnZXQgc3lzX3JlZl9jbGsu
DQoNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBuZWVkX3RvX3N3aXRjaF9mcmVxKHZv
aWQpDQo+ID4gK3sNCj4gPiArCXUzMiBzdnI7DQo+ID4gKw0KPiA+ICsJc3ZyID0gbWZzcHIoU1BS
Tl9TVlIpOw0KPiA+ICsJaWYgKFNWUl9TT0NfVkVSKHN2cikgPT0gU1ZSX1QxMDQwIHx8DQo+ID4g
KwkJCVNWUl9TT0NfVkVSKHN2cikgPT0gU1ZSX1QxMDQyKQ0KPiA+ICsJCXJldHVybiAxOw0KPiAN
Cj4gRXhwbGFpbiB3aHkgdGhpcyBpcyBzcGVjaWZpYyB0byBUMTA0eC4NCj4gDQoNCk1waWMgdGlt
ZXIgZnJlcSB3aWxsIGJlIGNoYW5nZSB3aGVuIHN5c3RlbSBnb2luZyB0byBkZWVwIHNsZWVwLiBT
byB3ZSBuZWVkIHRvIHJlY2FsY3VsYXRlIHRoZSB0aW1lLg0KDQo+IC1TY290dA0KPiANCg0K
^ permalink raw reply
* RE: [PATCH v3] dmaengine: driver support for FSL RaidEngine device.
From: Xuelin Shi @ 2014-04-15 3:07 UTC (permalink / raw)
To: Dan Williams
Cc: Harninder Rai, andriy.shevchenko@intel.com, Koul, Vinod,
Naveen Burmi, dmaengine@vger.kernel.org, linuxppc-dev
In-Reply-To: <CAPcyv4go1ghjD7fiEzwPJmcjRMBv7p0t7Sm9Ki=1Hu-0GKqoCQ@mail.gmail.com>
WWVzLCAiZGVwZW5kIG9uICFBU1lOQ19UWF9DSEFOTkVMX1NXSVRDSCIgaXMgYmV0dGVyIHNpbmNl
IGZzbGRtYSBzZWxlY3RzIHRoaXMgY29uZGl0aW9uLg0KDQpUaGFua3MsDQpYdWVsaW4gU2hpDQoN
Ci0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQpGcm9tOiBEYW4gV2lsbGlhbXMgW21haWx0bzpk
YW4uai53aWxsaWFtc0BpbnRlbC5jb21dIA0KU2VudDogMjAxNMTqNNTCMTXI1SA4OjMwDQpUbzog
U2hpIFh1ZWxpbi1CMjkyMzcNCkNjOiBLb3VsLCBWaW5vZDsgYW5kcml5LnNoZXZjaGVua29AaW50
ZWwuY29tOyBkbWFlbmdpbmVAdmdlci5rZXJuZWwub3JnOyBsaW51eHBwYy1kZXY7IFJhaSBIYXJu
aW5kZXItQjAxMDQ0OyBCdXJtaSBOYXZlZW4tQjE2NTAyDQpTdWJqZWN0OiBSZTogW1BBVENIIHYz
XSBkbWFlbmdpbmU6IGRyaXZlciBzdXBwb3J0IGZvciBGU0wgUmFpZEVuZ2luZSBkZXZpY2UuDQoN
Ck9uIFN1biwgQXByIDEzLCAyMDE0IGF0IDc6NDggUE0sIFh1ZWxpbiBTaGkgPHh1ZWxpbi5zaGlA
ZnJlZXNjYWxlLmNvbT4gd3JvdGU6DQo+IEhpIERhbiwNCj4NCj4gZnNsIGRtYSBkZXZpY2UgYW5k
IGZzbCByYWlkIGRldmljZSBhcmUgdHdvIGRpZmZlcmVuY3QgZGV2aWNlcyB0aGF0IA0KPiBib3Ro
IHByb3ZpZGUgYXN5bmNfbWVtY3B5IGNhcGFiaWxpdHksIHNvIEkgdXNlICFGU0xfRE1BIHRvIGRp
c2FibGUgdGhlIGZzbCBkbWEgZGV2aWNlLg0KPg0KPiBUaGF0J3MgdG8gc2F5LCBlaXRoZXIgc2Vs
ZWN0IGZzbGRtYSBkZXZpY2UsIGVpdGhlciBmc2wgcmFpZCBkZXZpY2UuDQo+DQoNClJpZ2h0LCBi
dXQgdGhhdCdzIG5vdCB3aGF0IHlvdXIgcHJvcG9zZWQgS2NvbmZpZyBkZXBlbmRlbmN5IGxpbmUg
ZG9lcy4NCg0KWW91IHdhbnQgc29tZXRoaW5nIGxpa2UgImRlcGVuZHMgb24gRlNMX1NPQyAmJiAh
KEZTTF9ETUEgfHwgRlNMX0RNQT1tKSINCg0KSG93ZXZlciwgdGhlIG1vcmUgcHJvYmxlbWF0aWMg
b3B0aW9uIGlzIEFTWU5DX1RYX0NIQU5ORUxfU1dJVENILiAgVGhhdCBvcHRpb24gaXMgcHJvYmxl
bWF0aWMgZm9yIFJBSUQsIHNvIEkgcHJvcG9zZSAiZGVwZW5kIG9uICFBU1lOQ19UWF9DSEFOTkVM
X1NXSVRDSCIgc2luY2UgdGhhdCBhZGRyZXNzZXMgYm90aCBwcm9ibGVtcy4NCg0KDQo=
^ permalink raw reply
* Re: [PATCH] ASoC: fsl_sai: Fix incorrect condition check in trigger()
From: Nicolin Chen @ 2014-04-15 2:33 UTC (permalink / raw)
To: Mark Brown; +Cc: alsa-devel, Li.Xiubo, linuxppc-dev, linux-kernel, timur
In-Reply-To: <20140414203126.GB25182@sirena.org.uk>
On Mon, Apr 14, 2014 at 09:31:26PM +0100, Mark Brown wrote:
> On Fri, Apr 11, 2014 at 10:10:00PM +0800, Nicolin Chen wrote:
>
> > + /* Check if the opposite FRDE is also disabled */
> > + if (!(tx ? rcsr & FSL_SAI_CSR_FRDE : tcsr & FSL_SAI_CSR_FRDE)) {
>
> I've applied this since it's a fix but this is *not* a triumph of
> legibility, the ternery operator is often not helpful.
It looks like I've got a bad habit again. I'll be careful next time.
Thank you for reminding me,
Nicolin
^ permalink raw reply
* Re: [PATCH v2 2/2] ARM: dts: Append clock bindings for sai2 on VF610 platform
From: Nicolin Chen @ 2014-04-15 2:28 UTC (permalink / raw)
To: Mark Brown
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo, rob,
galak, shawn.guo, linuxppc-dev
In-Reply-To: <20140414203851.GD25182@sirena.org.uk>
On Mon, Apr 14, 2014 at 09:38:51PM +0100, Mark Brown wrote:
> On Wed, Apr 02, 2014 at 06:10:20PM +0800, Nicolin Chen wrote:
> > Since we added fours clock to the DT binding, we should update the current
> > SAI dts/dtsi so as not to break their functions.
>
> This doesn't apply against v3.15-rc1, can you please check and resend?
Please disregard this patch, since my v6 patch was compatible with the old
binding, the patch here is provisionally useless and I can later send it
via Shawn's tree.
Thank you,
Nicolin
^ permalink raw reply
* Re: [PATCH v2 1/2] ASoC: fsl_sai: Add clock controls for SAI
From: Nicolin Chen @ 2014-04-15 2:26 UTC (permalink / raw)
To: Mark Brown
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo, rob,
galak, shawn.guo, linuxppc-dev
In-Reply-To: <20140414204331.GE25182@sirena.org.uk>
On Mon, Apr 14, 2014 at 09:43:31PM +0100, Mark Brown wrote:
> On Wed, Apr 02, 2014 at 06:10:19PM +0800, Nicolin Chen wrote:
>
> > -- clock-names : Must include the "sai" entry.
> > +- clock-names : Must include the "bus" for register access and "mclk1" "mclk2"
> > + "mclk3" for bit clock and frame clock providing.
>
> This breaks compatibilty with old DTs - it just removes the "sai" name.
> It's OK to deprecate the "sai" clock name but you need to keep support
> for DTs that only specify that, there's no code for that left in the
> driver.
Sir, you've already applied the v6 of this patch last week :)
And I can still find it in topic/fsl-sai.
ca3e35c ASoC: fsl_sai: Add clock controls for SAI
And regarding the old DTs compatibilty, Shawn has already reminded me
in his comments against one of the version. I took his advice and made
the patch compatible with the old 'sai' clock binding within that v6.
Thank you,
Nicolin
^ permalink raw reply
* RE: [PATCH 1/2] powerpc/mpc85xx: add two functions to get suspend state which is standby or mem
From: Dongsheng.Wang @ 2014-04-15 2:19 UTC (permalink / raw)
To: Scott Wood
Cc: linuxppc-dev@lists.ozlabs.org, chenhui.zhao@freescale.com,
Jason.Jin@freescale.com
In-Reply-To: <1397518031.20280.229.camel@snotra.buserror.net>
DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogV29vZCBTY290dC1CMDc0
MjENCj4gU2VudDogVHVlc2RheSwgQXByaWwgMTUsIDIwMTQgNzoyNyBBTQ0KPiBUbzogV2FuZyBE
b25nc2hlbmctQjQwNTM0DQo+IENjOiBKaW4gWmhlbmd4aW9uZy1SNjQxODg7IExpIFlhbmctTGVv
LVI1ODQ3MjsgWmhhbyBDaGVuaHVpLUIzNTMzNjsgbGludXhwcGMtDQo+IGRldkBsaXN0cy5vemxh
YnMub3JnDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggMS8yXSBwb3dlcnBjL21wYzg1eHg6IGFkZCB0
d28gZnVuY3Rpb25zIHRvIGdldCBzdXNwZW5kIHN0YXRlDQo+IHdoaWNoIGlzIHN0YW5kYnkgb3Ig
bWVtDQo+IA0KPiBPbiBNb24sIDIwMTQtMDQtMTQgYXQgMTA6MjQgKzA4MDAsIERvbmdzaGVuZyBX
YW5nIHdyb3RlOg0KPiA+IEZyb206IFdhbmcgRG9uZ3NoZW5nIDxkb25nc2hlbmcud2FuZ0BmcmVl
c2NhbGUuY29tPg0KPiA+DQo+ID4gQWRkIHNldF9wbV9zdXNwZW5kX3N0YXRlICYgcG1fc3VzcGVu
ZF9zdGF0ZSBmdW5jdGlvbnMgdG8gc2V0L2dldCBzdXNwZW5kIHN0YXRlLg0KPiA+IFdoZW4gc3lz
dGVtIGdvaW5nIHRvIHNsZWVwLCBkZXZpY2VzIGNhbiBnZXQgdGhlIHN5c3RlbSBzdXNwZW5kDQo+
ID4gc3RhdGUoU1RBTkRCWS9NRU0pIHRocm91Z2ggcG1fc3VzcGVuZF9zdGF0ZSBmdW5jdGlvbiBh
bmQgaGFuZGxlIGRpZmZlcmVudA0KPiBzaXR1YXRpb25zLg0KPiA+DQo+ID4gU2lnbmVkLW9mZi1i
eTogV2FuZyBEb25nc2hlbmcgPGRvbmdzaGVuZy53YW5nQGZyZWVzY2FsZS5jb20+DQo+ID4NCj4g
PiBkaWZmIC0tZ2l0IGEvYXJjaC9wb3dlcnBjL3BsYXRmb3Jtcy84NXh4L2NvbW1vbi5jDQo+ID4g
Yi9hcmNoL3Bvd2VycGMvcGxhdGZvcm1zLzg1eHgvY29tbW9uLmMNCj4gPiBpbmRleCBiNTY0YjVl
Li4zODUzZDQzIDEwMDY0NA0KPiA+IC0tLSBhL2FyY2gvcG93ZXJwYy9wbGF0Zm9ybXMvODV4eC9j
b21tb24uYw0KPiA+ICsrKyBiL2FyY2gvcG93ZXJwYy9wbGF0Zm9ybXMvODV4eC9jb21tb24uYw0K
PiA+IEBAIC04LDYgKzgsNyBAQA0KPiA+DQo+ID4gICNpbmNsdWRlIDxsaW51eC9vZl9pcnEuaD4N
Cj4gPiAgI2luY2x1ZGUgPGxpbnV4L29mX3BsYXRmb3JtLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51
eC9zdXNwZW5kLmg+DQo+ID4NCj4gPiAgI2luY2x1ZGUgPGFzbS9xZS5oPg0KPiA+ICAjaW5jbHVk
ZSA8c3lzZGV2L2NwbTJfcGljLmg+DQo+ID4gQEAgLTQ3LDYgKzQ4LDE5IEBAIGludCBfX2luaXQg
bXBjODV4eF9jb21tb25fcHVibGlzaF9kZXZpY2VzKHZvaWQpDQo+ID4gIHsNCj4gPiAgCXJldHVy
biBvZl9wbGF0Zm9ybV9idXNfcHJvYmUoTlVMTCwgbXBjODV4eF9jb21tb25faWRzLCBOVUxMKTsg
IH0NCj4gPiArDQo+ID4gK3N0YXRpYyBzdXNwZW5kX3N0YXRlX3QgcG1fc3RhdGU7DQo+ID4gKw0K
PiA+ICt2b2lkIHNldF9wbV9zdXNwZW5kX3N0YXRlKHN1c3BlbmRfc3RhdGVfdCBzdGF0ZSkgew0K
PiA+ICsJcG1fc3RhdGUgPSBzdGF0ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3VzcGVuZF9zdGF0
ZV90IHBtX3N1c3BlbmRfc3RhdGUodm9pZCkgew0KPiA+ICsJcmV0dXJuIHBtX3N0YXRlOw0KPiA+
ICt9DQo+IA0KPiBUaGVzZSBuZWVkIHRvIGJlIG5hbWVzcGFjZWQgdG8gaW5kaWNhdGUgdGhhdCB0
aGV5IGFwcGx5IG9ubHkgdG8gbXBjODV4eC4NCj4gV2hlcmUgZG8geW91IHBsYW4gb24gdXNpbmcg
dGhlc2UgZnJvbSwgdGhhdCBtcGM4NXh4IGNhbiBiZSBzYWZlbHkgYXNzdW1lZD8NCj4gDQoNCk1w
aWMgdGltZXIgYW5kIFBDSWUgZHJpdmVyLg0KDQo+IFRoaXMgc2VlbXMgbGlrZSBhIGZlYXR1cmUg
dGhhdCBzaG91bGQgYmUgaW1wbGVtZW50ZWQgaW4gZ2VuZXJpYyBjb2RlIGluc3RlYWQuDQo+IA0K
DQpPSywgSSB3aWxsIG1vdmUgdGhpcyB0byBhIGdlbmVyaWMgcGF0aC4NCg0KUmVnYXJkcywNCi1E
b25nc2hlbmcNCg0KPiAtU2NvdHQNCj4gDQoNCg==
^ permalink raw reply
* Re: [PATCH v3] dmaengine: driver support for FSL RaidEngine device.
From: Dan Williams @ 2014-04-15 0:30 UTC (permalink / raw)
To: Xuelin Shi
Cc: Harninder Rai, andriy.shevchenko@intel.com, Koul, Vinod,
Naveen Burmi, dmaengine@vger.kernel.org, linuxppc-dev
In-Reply-To: <0c8d1963a25648f8a8f820bbc55afe4f@BL2PR03MB147.namprd03.prod.outlook.com>
On Sun, Apr 13, 2014 at 7:48 PM, Xuelin Shi <xuelin.shi@freescale.com> wrote:
> Hi Dan,
>
> fsl dma device and fsl raid device are two differenct devices that both provide async_memcpy
> capability, so I use !FSL_DMA to disable the fsl dma device.
>
> That's to say, either select fsldma device, either fsl raid device.
>
Right, but that's not what your proposed Kconfig dependency line does.
You want something like "depends on FSL_SOC && !(FSL_DMA || FSL_DMA=m)"
However, the more problematic option is ASYNC_TX_CHANNEL_SWITCH. That
option is problematic for RAID, so I propose "depend on
!ASYNC_TX_CHANNEL_SWITCH" since that addresses both problems.
^ permalink raw reply
* Re: [PATCH 2/2] fsl/mpic_timer: make mpic_timer to support deep sleep feature
From: Scott Wood @ 2014-04-14 23:35 UTC (permalink / raw)
To: Dongsheng Wang; +Cc: linuxppc-dev, chenhui.zhao, jason.jin
In-Reply-To: <1397442250-14886-2-git-send-email-dongsheng.wang@freescale.com>
On Mon, 2014-04-14 at 10:24 +0800, Dongsheng Wang wrote:
> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>
> At T104x platfrom the timer clock will be changed when system going to
> deep sleep.
Could you elaborate on what is changing and why?
> +#include <asm/mpc85xx.h>
> #include <asm/mpic_timer.h>
So much for, "The driver currently is only tested on fsl chip, but it
can potentially support other global timers complying to OpenPIC
standard."
> #define FSL_GLOBAL_TIMER 0x1
> @@ -71,8 +74,10 @@ struct timer_group_priv {
> struct timer_regs __iomem *regs;
> struct mpic_timer timer[TIMERS_PER_GROUP];
> struct list_head node;
> + unsigned long idle;
> unsigned int timerfreq;
> - unsigned int idle;
Why?
> + unsigned int suspended_timerfreq;
> + unsigned int resume_timerfreq;
> unsigned int flags;
> spinlock_t lock;
> void __iomem *group_tcr;
> @@ -88,6 +93,7 @@ static struct cascade_priv cascade_timer[] = {
> };
>
> static LIST_HEAD(timer_group_list);
> +static int switch_freq_flag;
Needs documentation, and based on "_flag" it should probably be a bool.
> static void convert_ticks_to_time(struct timer_group_priv *priv,
> const u64 ticks, struct timeval *time)
> @@ -423,6 +429,33 @@ struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
> }
> EXPORT_SYMBOL(mpic_request_timer);
>
> +static void timer_group_get_suspended_freq(struct timer_group_priv *priv)
> +{
> + struct device_node *np;
> +
> + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-clockgen-2.0");
> + if (!np) {
> + pr_err("mpic timer: Missing clockgen device node.\n");
Why is it an error to not have a 2.0 QorIQ clockgen?
> + return;
> + }
> +
> + of_property_read_u32(np, "clock-frequency", &priv->suspended_timerfreq);
> + of_node_put(np);
Shouldn't this go through the clock API?
> +}
> +
> +static int need_to_switch_freq(void)
> +{
> + u32 svr;
> +
> + svr = mfspr(SPRN_SVR);
> + if (SVR_SOC_VER(svr) == SVR_T1040 ||
> + SVR_SOC_VER(svr) == SVR_T1042)
> + return 1;
Explain why this is specific to T104x.
-Scott
^ permalink raw reply
* Re: [PATCH 1/2] powerpc/mpc85xx: add two functions to get suspend state which is standby or mem
From: Scott Wood @ 2014-04-14 23:27 UTC (permalink / raw)
To: Dongsheng Wang; +Cc: linuxppc-dev, chenhui.zhao, jason.jin
In-Reply-To: <1397442250-14886-1-git-send-email-dongsheng.wang@freescale.com>
On Mon, 2014-04-14 at 10:24 +0800, Dongsheng Wang wrote:
> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>
> Add set_pm_suspend_state & pm_suspend_state functions to set/get suspend state.
> When system going to sleep, devices can get the system suspend state(STANDBY/MEM)
> through pm_suspend_state function and handle different situations.
>
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
>
> diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c
> index b564b5e..3853d43 100644
> --- a/arch/powerpc/platforms/85xx/common.c
> +++ b/arch/powerpc/platforms/85xx/common.c
> @@ -8,6 +8,7 @@
>
> #include <linux/of_irq.h>
> #include <linux/of_platform.h>
> +#include <linux/suspend.h>
>
> #include <asm/qe.h>
> #include <sysdev/cpm2_pic.h>
> @@ -47,6 +48,19 @@ int __init mpc85xx_common_publish_devices(void)
> {
> return of_platform_bus_probe(NULL, mpc85xx_common_ids, NULL);
> }
> +
> +static suspend_state_t pm_state;
> +
> +void set_pm_suspend_state(suspend_state_t state)
> +{
> + pm_state = state;
> +}
> +
> +suspend_state_t pm_suspend_state(void)
> +{
> + return pm_state;
> +}
These need to be namespaced to indicate that they apply only to mpc85xx.
Where do you plan on using these from, that mpc85xx can be safely
assumed?
This seems like a feature that should be implemented in generic code
instead.
-Scott
^ permalink raw reply
* Re: [PATCH] powerpc/85xx: Add OCA4080 board support
From: Scott Wood @ 2014-04-14 22:28 UTC (permalink / raw)
To: Martijn de Gouw; +Cc: stef.van.os, Martijn de Gouw, linuxppc-dev
In-Reply-To: <1397478910-26361-1-git-send-email-martijn.de.gouw@prodrive-technologies.com>
On Mon, 2014-04-14 at 14:35 +0200, Martijn de Gouw wrote:
> + lbc: localbus@ffe124000 {
> + reg = <0xf 0xfe124000 0 0x1000>;
> + ranges = <0 0 0xf 0xef800000 0x800000>;
> +
> + flash@0,0 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "cfi-flash";
> + reg = <0 0 0x00800000>;
> + bank-width = <2>;
> + device-width = <2>;
> + partition@rcw {
> + label = "rcw";
> + reg = <0x00000000 0x00020000>;
> + };
> + partition@fman-ucode {
> + label = "fman-ucode";
> + reg = <0x00020000 0x00020000>;
> + };
> + partition@user {
> + label = "user";
> + reg = <0x00040000 0x00680000>;
> + };
> + partition@env0 {
> + label = "env0";
> + reg = <0x006c0000 0x00020000>;
> + };
> + partition@env1 {
> + label = "env1";
> + reg = <0x006e0000 0x00020000>;
> + };
> + partition@u-boot {
> + label = "u-boot";
> + reg = <0x00700000 0x00080000>;
> + };
> + partition@u-boot-backup {
> + label = "u-boot-backup";
> + reg = <0x00780000 0x00080000>;
> + };
These are not valid unit addresses. Regardless, please don't put
partition info in the dts.
-Scott
^ permalink raw reply
* [PATCH 18/20] cpufreq: pasemi: Use cpufreq_for_each_entry macro for iteration
From: Stratos Karafotis @ 2014-04-14 21:10 UTC (permalink / raw)
To: Olof Johansson, Rafael J. Wysocki, Viresh Kumar
Cc: linuxppc-dev, LKML, cpufreq@vger.kernel.org,
linux-pm@vger.kernel.org
The cpufreq core supports the cpufreq_for_each_entry macro helper
for iteration over the cpufreq_frequency_table, so use it.
It should have no functional changes.
Signed-off-by: Stratos Karafotis <stratosk@semaphore.gr>
---
Please note that I was no able to compile test this patch due to
lack of cross compiler.
drivers/cpufreq/pasemi-cpufreq.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index 84c84b5..9a64492 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -136,9 +136,10 @@ void restore_astate(int cpu)
static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
+ struct cpufreq_frequency_table *pos;
const u32 *max_freqp;
u32 max_freq;
- int i, cur_astate;
+ int cur_astate;
struct resource res;
struct device_node *cpu, *dn;
int err = -ENODEV;
@@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n");
/* initialize frequency table */
- for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
- pas_freqs[i].frequency =
- get_astate_freq(pas_freqs[i].driver_data) * 100000;
- pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
+ cpufreq_for_each_entry(pos, pas_freqs) {
+ pos->frequency = get_astate_freq(pos->driver_data) * 100000;
+ pr_debug("%lu: %d\n", pos - pas_freqs, pos->frequency);
}
cur_astate = get_cur_astate(policy->cpu);
--
1.9.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox