Path: blob/master/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c
26481 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* The driver for Freescale MPC512x LocalPlus Bus FIFO3* (called SCLPC in the Reference Manual).4*5* Copyright (C) 2013-2015 Alexander Popov <[email protected]>.6*/78#include <linux/interrupt.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/of.h>12#include <linux/of_address.h>13#include <linux/of_irq.h>14#include <linux/platform_device.h>15#include <asm/mpc5121.h>16#include <asm/io.h>17#include <linux/spinlock.h>18#include <linux/slab.h>19#include <linux/dmaengine.h>20#include <linux/dma-direction.h>21#include <linux/dma-mapping.h>2223#define DRV_NAME "mpc512x_lpbfifo"2425struct cs_range {26u32 csnum;27u32 base; /* must be zero */28u32 addr;29u32 size;30};3132static struct lpbfifo_data {33spinlock_t lock; /* for protecting lpbfifo_data */34phys_addr_t regs_phys;35resource_size_t regs_size;36struct mpc512x_lpbfifo __iomem *regs;37int irq;38struct cs_range *cs_ranges;39size_t cs_n;40struct dma_chan *chan;41struct mpc512x_lpbfifo_request *req;42dma_addr_t ram_bus_addr;43bool wait_lpbfifo_irq;44bool wait_lpbfifo_callback;45} lpbfifo;4647/*48* A data transfer from RAM to some device on LPB is finished49* when both mpc512x_lpbfifo_irq() and mpc512x_lpbfifo_callback()50* have been called. We execute the callback registered in51* mpc512x_lpbfifo_request just after that.52* But for a data transfer from some device on LPB to RAM we don't enable53* LPBFIFO interrupt because clearing MPC512X_SCLPC_SUCCESS interrupt flag54* automatically disables LPBFIFO reading request to the DMA controller55* and the data transfer hangs. So the callback registered in56* mpc512x_lpbfifo_request is executed at the end of mpc512x_lpbfifo_callback().57*/5859/*60* mpc512x_lpbfifo_irq - IRQ handler for LPB FIFO61*/62static irqreturn_t mpc512x_lpbfifo_irq(int irq, void *param)63{64struct device *dev = (struct device *)param;65struct mpc512x_lpbfifo_request *req = NULL;66unsigned long flags;67u32 status;6869spin_lock_irqsave(&lpbfifo.lock, flags);7071if (!lpbfifo.regs)72goto end;7374req = lpbfifo.req;75if (!req || req->dir == MPC512X_LPBFIFO_REQ_DIR_READ) {76dev_err(dev, "bogus LPBFIFO IRQ\n");77goto end;78}7980status = in_be32(&lpbfifo.regs->status);81if (status != MPC512X_SCLPC_SUCCESS) {82dev_err(dev, "DMA transfer from RAM to peripheral failed\n");83out_be32(&lpbfifo.regs->enable,84MPC512X_SCLPC_RESET | MPC512X_SCLPC_FIFO_RESET);85goto end;86}87/* Clear the interrupt flag */88out_be32(&lpbfifo.regs->status, MPC512X_SCLPC_SUCCESS);8990lpbfifo.wait_lpbfifo_irq = false;9192if (lpbfifo.wait_lpbfifo_callback)93goto end;9495/* Transfer is finished, set the FIFO as idle */96lpbfifo.req = NULL;9798spin_unlock_irqrestore(&lpbfifo.lock, flags);99100if (req->callback)101req->callback(req);102103return IRQ_HANDLED;104105end:106spin_unlock_irqrestore(&lpbfifo.lock, flags);107return IRQ_HANDLED;108}109110/*111* mpc512x_lpbfifo_callback is called by DMA driver when112* DMA transaction is finished.113*/114static void mpc512x_lpbfifo_callback(void *param)115{116unsigned long flags;117struct mpc512x_lpbfifo_request *req = NULL;118enum dma_data_direction dir;119120spin_lock_irqsave(&lpbfifo.lock, flags);121122if (!lpbfifo.regs) {123spin_unlock_irqrestore(&lpbfifo.lock, flags);124return;125}126127req = lpbfifo.req;128if (!req) {129pr_err("bogus LPBFIFO callback\n");130spin_unlock_irqrestore(&lpbfifo.lock, flags);131return;132}133134/* Release the mapping */135if (req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE)136dir = DMA_TO_DEVICE;137else138dir = DMA_FROM_DEVICE;139dma_unmap_single(lpbfifo.chan->device->dev,140lpbfifo.ram_bus_addr, req->size, dir);141142lpbfifo.wait_lpbfifo_callback = false;143144if (!lpbfifo.wait_lpbfifo_irq) {145/* Transfer is finished, set the FIFO as idle */146lpbfifo.req = NULL;147148spin_unlock_irqrestore(&lpbfifo.lock, flags);149150if (req->callback)151req->callback(req);152} else {153spin_unlock_irqrestore(&lpbfifo.lock, flags);154}155}156157static int mpc512x_lpbfifo_kick(void)158{159u32 bits;160bool no_incr = false;161u32 bpt = 32; /* max bytes per LPBFIFO transaction involving DMA */162u32 cs = 0;163size_t i;164struct dma_device *dma_dev = NULL;165struct scatterlist sg;166enum dma_data_direction dir;167struct dma_slave_config dma_conf = {};168struct dma_async_tx_descriptor *dma_tx = NULL;169dma_cookie_t cookie;170int ret;171172/*173* 1. Fit the requirements:174* - the packet size must be a multiple of 4 since FIFO Data Word175* Register allows only full-word access according the Reference176* Manual;177* - the physical address of the device on LPB and the packet size178* must be aligned on BPT (bytes per transaction) or 8-bytes179* boundary according the Reference Manual;180* - but we choose DMA maxburst equal (or very close to) BPT to prevent181* DMA controller from overtaking FIFO and causing FIFO underflow182* error. So we force the packet size to be aligned on BPT boundary183* not to confuse DMA driver which requires the packet size to be184* aligned on maxburst boundary;185* - BPT should be set to the LPB device port size for operation with186* disabled auto-incrementing according Reference Manual.187*/188if (lpbfifo.req->size == 0 || !IS_ALIGNED(lpbfifo.req->size, 4))189return -EINVAL;190191if (lpbfifo.req->portsize != LPB_DEV_PORTSIZE_UNDEFINED) {192bpt = lpbfifo.req->portsize;193no_incr = true;194}195196while (bpt > 1) {197if (IS_ALIGNED(lpbfifo.req->dev_phys_addr, min(bpt, 0x8u)) &&198IS_ALIGNED(lpbfifo.req->size, bpt)) {199break;200}201202if (no_incr)203return -EINVAL;204205bpt >>= 1;206}207dma_conf.dst_maxburst = max(bpt, 0x4u) / 4;208dma_conf.src_maxburst = max(bpt, 0x4u) / 4;209210for (i = 0; i < lpbfifo.cs_n; i++) {211phys_addr_t cs_start = lpbfifo.cs_ranges[i].addr;212phys_addr_t cs_end = cs_start + lpbfifo.cs_ranges[i].size;213phys_addr_t access_start = lpbfifo.req->dev_phys_addr;214phys_addr_t access_end = access_start + lpbfifo.req->size;215216if (access_start >= cs_start && access_end <= cs_end) {217cs = lpbfifo.cs_ranges[i].csnum;218break;219}220}221if (i == lpbfifo.cs_n)222return -EFAULT;223224/* 2. Prepare DMA */225dma_dev = lpbfifo.chan->device;226227if (lpbfifo.req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE) {228dir = DMA_TO_DEVICE;229dma_conf.direction = DMA_MEM_TO_DEV;230dma_conf.dst_addr = lpbfifo.regs_phys +231offsetof(struct mpc512x_lpbfifo, data_word);232} else {233dir = DMA_FROM_DEVICE;234dma_conf.direction = DMA_DEV_TO_MEM;235dma_conf.src_addr = lpbfifo.regs_phys +236offsetof(struct mpc512x_lpbfifo, data_word);237}238dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;239dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;240241/* Make DMA channel work with LPB FIFO data register */242if (dma_dev->device_config(lpbfifo.chan, &dma_conf))243return -EINVAL;244245sg_init_table(&sg, 1);246247sg_dma_address(&sg) = dma_map_single(dma_dev->dev,248lpbfifo.req->ram_virt_addr, lpbfifo.req->size, dir);249if (dma_mapping_error(dma_dev->dev, sg_dma_address(&sg)))250return -EFAULT;251252lpbfifo.ram_bus_addr = sg_dma_address(&sg); /* For freeing later */253254sg_dma_len(&sg) = lpbfifo.req->size;255256dma_tx = dmaengine_prep_slave_sg(lpbfifo.chan, &sg,2571, dma_conf.direction, 0);258if (!dma_tx) {259ret = -ENOSPC;260goto err_dma_prep;261}262dma_tx->callback = mpc512x_lpbfifo_callback;263dma_tx->callback_param = NULL;264265/* 3. Prepare FIFO */266out_be32(&lpbfifo.regs->enable,267MPC512X_SCLPC_RESET | MPC512X_SCLPC_FIFO_RESET);268out_be32(&lpbfifo.regs->enable, 0x0);269270/*271* Configure the watermarks for write operation (RAM->DMA->FIFO->dev):272* - high watermark 7 words according the Reference Manual,273* - low watermark 512 bytes (half of the FIFO).274* These watermarks don't work for read operation since the275* MPC512X_SCLPC_FLUSH bit is set (according the Reference Manual).276*/277out_be32(&lpbfifo.regs->fifo_ctrl, MPC512X_SCLPC_FIFO_CTRL(0x7));278out_be32(&lpbfifo.regs->fifo_alarm, MPC512X_SCLPC_FIFO_ALARM(0x200));279280/*281* Start address is a physical address of the region which belongs282* to the device on the LocalPlus Bus283*/284out_be32(&lpbfifo.regs->start_addr, lpbfifo.req->dev_phys_addr);285286/*287* Configure chip select, transfer direction, address increment option288* and bytes per transaction option289*/290bits = MPC512X_SCLPC_CS(cs);291if (lpbfifo.req->dir == MPC512X_LPBFIFO_REQ_DIR_READ)292bits |= MPC512X_SCLPC_READ | MPC512X_SCLPC_FLUSH;293if (no_incr)294bits |= MPC512X_SCLPC_DAI;295bits |= MPC512X_SCLPC_BPT(bpt);296out_be32(&lpbfifo.regs->ctrl, bits);297298/* Unmask irqs */299bits = MPC512X_SCLPC_ENABLE | MPC512X_SCLPC_ABORT_INT_ENABLE;300if (lpbfifo.req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE)301bits |= MPC512X_SCLPC_NORM_INT_ENABLE;302else303lpbfifo.wait_lpbfifo_irq = false;304305out_be32(&lpbfifo.regs->enable, bits);306307/* 4. Set packet size and kick FIFO off */308bits = lpbfifo.req->size | MPC512X_SCLPC_START;309out_be32(&lpbfifo.regs->pkt_size, bits);310311/* 5. Finally kick DMA off */312cookie = dma_tx->tx_submit(dma_tx);313if (dma_submit_error(cookie)) {314ret = -ENOSPC;315goto err_dma_submit;316}317318return 0;319320err_dma_submit:321out_be32(&lpbfifo.regs->enable,322MPC512X_SCLPC_RESET | MPC512X_SCLPC_FIFO_RESET);323err_dma_prep:324dma_unmap_single(dma_dev->dev, sg_dma_address(&sg),325lpbfifo.req->size, dir);326return ret;327}328329static int mpc512x_lpbfifo_submit_locked(struct mpc512x_lpbfifo_request *req)330{331int ret = 0;332333if (!lpbfifo.regs)334return -ENODEV;335336/* Check whether a transfer is in progress */337if (lpbfifo.req)338return -EBUSY;339340lpbfifo.wait_lpbfifo_irq = true;341lpbfifo.wait_lpbfifo_callback = true;342lpbfifo.req = req;343344ret = mpc512x_lpbfifo_kick();345if (ret != 0)346lpbfifo.req = NULL; /* Set the FIFO as idle */347348return ret;349}350351int mpc512x_lpbfifo_submit(struct mpc512x_lpbfifo_request *req)352{353unsigned long flags;354int ret = 0;355356spin_lock_irqsave(&lpbfifo.lock, flags);357ret = mpc512x_lpbfifo_submit_locked(req);358spin_unlock_irqrestore(&lpbfifo.lock, flags);359360return ret;361}362EXPORT_SYMBOL(mpc512x_lpbfifo_submit);363364/*365* LPBFIFO driver uses "ranges" property of "localbus" device tree node366* for being able to determine the chip select number of a client device367* ordering a DMA transfer.368*/369static int get_cs_ranges(struct device *dev)370{371int ret = -ENODEV;372struct device_node *lb_node;373size_t i = 0;374struct of_range_parser parser;375struct of_range range;376377lb_node = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-localbus");378if (!lb_node)379return ret;380381of_range_parser_init(&parser, lb_node);382lpbfifo.cs_n = of_range_count(&parser);383384lpbfifo.cs_ranges = devm_kcalloc(dev, lpbfifo.cs_n,385sizeof(struct cs_range), GFP_KERNEL);386if (!lpbfifo.cs_ranges)387goto end;388389for_each_of_range(&parser, &range) {390u32 base = lower_32_bits(range.bus_addr);391if (base)392goto end;393394lpbfifo.cs_ranges[i].csnum = upper_32_bits(range.bus_addr);395lpbfifo.cs_ranges[i].base = base;396lpbfifo.cs_ranges[i].addr = range.cpu_addr;397lpbfifo.cs_ranges[i].size = range.size;398i++;399}400401ret = 0;402403end:404of_node_put(lb_node);405return ret;406}407408static int mpc512x_lpbfifo_probe(struct platform_device *pdev)409{410struct resource r;411int ret = 0;412413memset(&lpbfifo, 0, sizeof(struct lpbfifo_data));414spin_lock_init(&lpbfifo.lock);415416lpbfifo.chan = dma_request_chan(&pdev->dev, "rx-tx");417if (IS_ERR(lpbfifo.chan))418return PTR_ERR(lpbfifo.chan);419420if (of_address_to_resource(pdev->dev.of_node, 0, &r) != 0) {421dev_err(&pdev->dev, "bad 'reg' in 'sclpc' device tree node\n");422ret = -ENODEV;423goto err0;424}425426lpbfifo.regs_phys = r.start;427lpbfifo.regs_size = resource_size(&r);428429if (!devm_request_mem_region(&pdev->dev, lpbfifo.regs_phys,430lpbfifo.regs_size, DRV_NAME)) {431dev_err(&pdev->dev, "unable to request region\n");432ret = -EBUSY;433goto err0;434}435436lpbfifo.regs = devm_ioremap(&pdev->dev,437lpbfifo.regs_phys, lpbfifo.regs_size);438if (!lpbfifo.regs) {439dev_err(&pdev->dev, "mapping registers failed\n");440ret = -ENOMEM;441goto err0;442}443444out_be32(&lpbfifo.regs->enable,445MPC512X_SCLPC_RESET | MPC512X_SCLPC_FIFO_RESET);446447if (get_cs_ranges(&pdev->dev) != 0) {448dev_err(&pdev->dev, "bad '/localbus' device tree node\n");449ret = -ENODEV;450goto err0;451}452453lpbfifo.irq = irq_of_parse_and_map(pdev->dev.of_node, 0);454if (!lpbfifo.irq) {455dev_err(&pdev->dev, "mapping irq failed\n");456ret = -ENODEV;457goto err0;458}459460if (request_irq(lpbfifo.irq, mpc512x_lpbfifo_irq, 0,461DRV_NAME, &pdev->dev) != 0) {462dev_err(&pdev->dev, "requesting irq failed\n");463ret = -ENODEV;464goto err1;465}466467dev_info(&pdev->dev, "probe succeeded\n");468return 0;469470err1:471irq_dispose_mapping(lpbfifo.irq);472err0:473dma_release_channel(lpbfifo.chan);474return ret;475}476477static void mpc512x_lpbfifo_remove(struct platform_device *pdev)478{479unsigned long flags;480struct dma_device *dma_dev = lpbfifo.chan->device;481struct mpc512x_lpbfifo __iomem *regs = NULL;482483spin_lock_irqsave(&lpbfifo.lock, flags);484regs = lpbfifo.regs;485lpbfifo.regs = NULL;486spin_unlock_irqrestore(&lpbfifo.lock, flags);487488dma_dev->device_terminate_all(lpbfifo.chan);489out_be32(®s->enable, MPC512X_SCLPC_RESET | MPC512X_SCLPC_FIFO_RESET);490491free_irq(lpbfifo.irq, &pdev->dev);492irq_dispose_mapping(lpbfifo.irq);493dma_release_channel(lpbfifo.chan);494}495496static const struct of_device_id mpc512x_lpbfifo_match[] = {497{ .compatible = "fsl,mpc512x-lpbfifo", },498{},499};500MODULE_DEVICE_TABLE(of, mpc512x_lpbfifo_match);501502static struct platform_driver mpc512x_lpbfifo_driver = {503.probe = mpc512x_lpbfifo_probe,504.remove = mpc512x_lpbfifo_remove,505.driver = {506.name = DRV_NAME,507.of_match_table = mpc512x_lpbfifo_match,508},509};510511module_platform_driver(mpc512x_lpbfifo_driver);512513MODULE_AUTHOR("Alexander Popov <[email protected]>");514MODULE_DESCRIPTION("MPC512x LocalPlus Bus FIFO device driver");515MODULE_LICENSE("GPL v2");516517518