]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/dma/imx-sdma.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / dma / imx-sdma.c
index d0602dd5d1b238eedf2500cd240ef0dc092800a8..b6d1455fa9362ecba3dbfe088df72bc77b2ef21e 100644 (file)
@@ -230,7 +230,7 @@ struct sdma_engine;
  * struct sdma_channel - housekeeping for a SDMA channel
  *
  * @sdma               pointer to the SDMA engine for this channel
- * @channel            the channel number, matches dmaengine chan_id
+ * @channel            the channel number, matches dmaengine chan_id + 1
  * @direction          transfer type. Needed for setting SDMA script
  * @peripheral_type    Peripheral type. Needed for setting SDMA script
  * @event_id0          aka dma request line
@@ -273,50 +273,6 @@ struct sdma_channel {
 #define MXC_SDMA_MIN_PRIORITY 1
 #define MXC_SDMA_MAX_PRIORITY 7
 
-/**
- * struct sdma_script_start_addrs - SDMA script start pointers
- *
- * start addresses of the different functions in the physical
- * address space of the SDMA engine.
- */
-struct sdma_script_start_addrs {
-       u32 ap_2_ap_addr;
-       u32 ap_2_bp_addr;
-       u32 ap_2_ap_fixed_addr;
-       u32 bp_2_ap_addr;
-       u32 loopback_on_dsp_side_addr;
-       u32 mcu_interrupt_only_addr;
-       u32 firi_2_per_addr;
-       u32 firi_2_mcu_addr;
-       u32 per_2_firi_addr;
-       u32 mcu_2_firi_addr;
-       u32 uart_2_per_addr;
-       u32 uart_2_mcu_addr;
-       u32 per_2_app_addr;
-       u32 mcu_2_app_addr;
-       u32 per_2_per_addr;
-       u32 uartsh_2_per_addr;
-       u32 uartsh_2_mcu_addr;
-       u32 per_2_shp_addr;
-       u32 mcu_2_shp_addr;
-       u32 ata_2_mcu_addr;
-       u32 mcu_2_ata_addr;
-       u32 app_2_per_addr;
-       u32 app_2_mcu_addr;
-       u32 shp_2_per_addr;
-       u32 shp_2_mcu_addr;
-       u32 mshc_2_mcu_addr;
-       u32 mcu_2_mshc_addr;
-       u32 spdif_2_mcu_addr;
-       u32 mcu_2_spdif_addr;
-       u32 asrc_2_mcu_addr;
-       u32 ext_mem_2_ipu_addr;
-       u32 descrambler_addr;
-       u32 dptc_dvfs_addr;
-       u32 utra_addr;
-       u32 ram_code_start_addr;
-};
-
 #define SDMA_FIRMWARE_MAGIC 0x414d4453
 
 /**
@@ -345,6 +301,7 @@ struct sdma_firmware_header {
 
 struct sdma_engine {
        struct device                   *dev;
+       struct device_dma_parameters    dma_parms;
        struct sdma_channel             channel[MAX_DMA_CHANNELS];
        struct sdma_channel_control     *channel_control;
        void __iomem                    *regs;
@@ -493,7 +450,7 @@ static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
                if (bd->mode.status & BD_RROR)
                        sdmac->status = DMA_ERROR;
                else
-                       sdmac->status = DMA_SUCCESS;
+                       sdmac->status = DMA_IN_PROGRESS;
 
                bd->mode.status |= BD_DONE;
                sdmac->buf_tail++;
@@ -814,15 +771,15 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
        __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
 }
 
-static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdma)
+static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdmac)
 {
-       dma_cookie_t cookie = sdma->chan.cookie;
+       dma_cookie_t cookie = sdmac->chan.cookie;
 
        if (++cookie < 0)
                cookie = 1;
 
-       sdma->chan.cookie = cookie;
-       sdma->desc.cookie = cookie;
+       sdmac->chan.cookie = cookie;
+       sdmac->desc.cookie = cookie;
 
        return cookie;
 }
@@ -842,7 +799,7 @@ static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
 
        cookie = sdma_assign_cookie(sdmac);
 
-       sdma_enable_channel(sdma, tx->chan->chan_id);
+       sdma_enable_channel(sdma, sdmac->channel);
 
        spin_unlock_irq(&sdmac->lock);
 
@@ -855,10 +812,6 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
        struct imx_dma_data *data = chan->private;
        int prio, ret;
 
-       /* No need to execute this for internal channel 0 */
-       if (chan->chan_id == 0)
-               return 0;
-
        if (!data)
                return -EINVAL;
 
@@ -923,7 +876,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
        int ret, i, count;
-       int channel = chan->chan_id;
+       int channel = sdmac->channel;
        struct scatterlist *sg;
 
        if (sdmac->status == DMA_IN_PROGRESS)
@@ -968,22 +921,33 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                        ret =  -EINVAL;
                        goto err_out;
                }
-               if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
+
+               switch (sdmac->word_size) {
+               case DMA_SLAVE_BUSWIDTH_4_BYTES:
                        bd->mode.command = 0;
-               else
-                       bd->mode.command = sdmac->word_size;
+                       if (count & 3 || sg->dma_address & 3)
+                               return NULL;
+                       break;
+               case DMA_SLAVE_BUSWIDTH_2_BYTES:
+                       bd->mode.command = 2;
+                       if (count & 1 || sg->dma_address & 1)
+                               return NULL;
+                       break;
+               case DMA_SLAVE_BUSWIDTH_1_BYTE:
+                       bd->mode.command = 1;
+                       break;
+               default:
+                       return NULL;
+               }
 
                param = BD_DONE | BD_EXTD | BD_CONT;
 
-               if (sdmac->flags & IMX_DMA_SG_LOOP) {
+               if (i + 1 == sg_len) {
                        param |= BD_INTR;
-                       if (i + 1 == sg_len)
-                               param |= BD_WRAP;
+                       param |= BD_LAST;
+                       param &= ~BD_CONT;
                }
 
-               if (i + 1 == sg_len)
-                       param |= BD_INTR;
-
                dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n",
                                i, count, sg->dma_address,
                                param & BD_WRAP ? "wrap" : "",
@@ -997,6 +961,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 
        return &sdmac->desc;
 err_out:
+       sdmac->status = DMA_ERROR;
        return NULL;
 }
 
@@ -1007,7 +972,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
        int num_periods = buf_len / period_len;
-       int channel = chan->chan_id;
+       int channel = sdmac->channel;
        int ret, i = 0, buf = 0;
 
        dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
@@ -1110,14 +1075,12 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        dma_cookie_t last_used;
-       enum dma_status ret;
 
        last_used = chan->cookie;
 
-       ret = dma_async_is_complete(cookie, sdmac->last_completed, last_used);
        dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0);
 
-       return ret;
+       return sdmac->status;
 }
 
 static void sdma_issue_pending(struct dma_chan *chan)
@@ -1127,8 +1090,74 @@ static void sdma_issue_pending(struct dma_chan *chan)
         */
 }
 
-static int __init sdma_init(struct sdma_engine *sdma,
-               void *ram_code, int ram_code_size)
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1        34
+
+static void sdma_add_scripts(struct sdma_engine *sdma,
+               const struct sdma_script_start_addrs *addr)
+{
+       s32 *addr_arr = (u32 *)addr;
+       s32 *saddr_arr = (u32 *)sdma->script_addrs;
+       int i;
+
+       for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
+               if (addr_arr[i] > 0)
+                       saddr_arr[i] = addr_arr[i];
+}
+
+static int __init sdma_get_firmware(struct sdma_engine *sdma,
+               const char *cpu_name, int to_version)
+{
+       const struct firmware *fw;
+       char *fwname;
+       const struct sdma_firmware_header *header;
+       int ret;
+       const struct sdma_script_start_addrs *addr;
+       unsigned short *ram_code;
+
+       fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", cpu_name, to_version);
+       if (!fwname)
+               return -ENOMEM;
+
+       ret = request_firmware(&fw, fwname, sdma->dev);
+       if (ret) {
+               kfree(fwname);
+               return ret;
+       }
+       kfree(fwname);
+
+       if (fw->size < sizeof(*header))
+               goto err_firmware;
+
+       header = (struct sdma_firmware_header *)fw->data;
+
+       if (header->magic != SDMA_FIRMWARE_MAGIC)
+               goto err_firmware;
+       if (header->ram_code_start + header->ram_code_size > fw->size)
+               goto err_firmware;
+
+       addr = (void *)header + header->script_addrs_start;
+       ram_code = (void *)header + header->ram_code_start;
+
+       clk_enable(sdma->clk);
+       /* download the RAM image for SDMA */
+       sdma_load_script(sdma, ram_code,
+                       header->ram_code_size,
+                       addr->ram_code_start_addr);
+       clk_disable(sdma->clk);
+
+       sdma_add_scripts(sdma, addr);
+
+       dev_info(sdma->dev, "loaded firmware %d.%d\n",
+                       header->version_major,
+                       header->version_minor);
+
+err_firmware:
+       release_firmware(fw);
+
+       return ret;
+}
+
+static int __init sdma_init(struct sdma_engine *sdma)
 {
        int i, ret;
        dma_addr_t ccb_phys;
@@ -1192,11 +1221,6 @@ static int __init sdma_init(struct sdma_engine *sdma,
 
        __raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR);
 
-       /* download the RAM image for SDMA */
-       sdma_load_script(sdma, ram_code,
-                       ram_code_size,
-                       sdma->script_addrs->ram_code_start_addr);
-
        /* Set bits of CONFIG register with given context switching mode */
        __raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
 
@@ -1216,16 +1240,10 @@ err_dma_alloc:
 static int __init sdma_probe(struct platform_device *pdev)
 {
        int ret;
-       const struct firmware *fw;
-       const struct sdma_firmware_header *header;
-       const struct sdma_script_start_addrs *addr;
        int irq;
-       unsigned short *ram_code;
        struct resource *iores;
        struct sdma_platform_data *pdata = pdev->dev.platform_data;
-       char *fwname;
        int i;
-       dma_cap_mask_t mask;
        struct sdma_engine *sdma;
 
        sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
@@ -1262,41 +1280,15 @@ static int __init sdma_probe(struct platform_device *pdev)
        if (ret)
                goto err_request_irq;
 
-       fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin",
-                       pdata->cpu_name, pdata->to_version);
-       if (!fwname) {
-               ret = -ENOMEM;
-               goto err_cputype;
-       }
-
-       ret = request_firmware(&fw, fwname, &pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "request firmware \"%s\" failed with %d\n",
-                               fwname, ret);
-               kfree(fwname);
-               goto err_cputype;
-       }
-       kfree(fwname);
-
-       if (fw->size < sizeof(*header))
-               goto err_firmware;
-
-       header = (struct sdma_firmware_header *)fw->data;
-
-       if (header->magic != SDMA_FIRMWARE_MAGIC)
-               goto err_firmware;
-       if (header->ram_code_start + header->ram_code_size > fw->size)
-               goto err_firmware;
-
-       addr = (void *)header + header->script_addrs_start;
-       ram_code = (void *)header + header->ram_code_start;
-       sdma->script_addrs = kmalloc(sizeof(*addr), GFP_KERNEL);
+       sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
        if (!sdma->script_addrs)
-               goto err_firmware;
-       memcpy(sdma->script_addrs, addr, sizeof(*addr));
+               goto err_alloc;
 
        sdma->version = pdata->sdma_version;
 
+       dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
+       dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
+
        INIT_LIST_HEAD(&sdma->dma_device.channels);
        /* Initialize channel parameters */
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
@@ -1305,21 +1297,28 @@ static int __init sdma_probe(struct platform_device *pdev)
                sdmac->sdma = sdma;
                spin_lock_init(&sdmac->lock);
 
-               dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
-               dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
-
                sdmac->chan.device = &sdma->dma_device;
-               sdmac->chan.chan_id = i;
                sdmac->channel = i;
 
-               /* Add the channel to the DMAC list */
-               list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels);
+               /*
+                * Add the channel to the DMAC list. Do not add channel 0 though
+                * because we need it internally in the SDMA driver. This also means
+                * that channel 0 in dmaengine counting matches sdma channel 1.
+                */
+               if (i)
+                       list_add_tail(&sdmac->chan.device_node,
+                                       &sdma->dma_device.channels);
        }
 
-       ret = sdma_init(sdma, ram_code, header->ram_code_size);
+       ret = sdma_init(sdma);
        if (ret)
                goto err_init;
 
+       if (pdata->script_addrs)
+               sdma_add_scripts(sdma, pdata->script_addrs);
+
+       sdma_get_firmware(sdma, pdata->cpu_name, pdata->to_version);
+
        sdma->dma_device.dev = &pdev->dev;
 
        sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
@@ -1329,6 +1328,8 @@ static int __init sdma_probe(struct platform_device *pdev)
        sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
        sdma->dma_device.device_control = sdma_control;
        sdma->dma_device.device_issue_pending = sdma_issue_pending;
+       sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
+       dma_set_max_seg_size(sdma->dma_device.dev, 65535);
 
        ret = dma_async_device_register(&sdma->dma_device);
        if (ret) {
@@ -1336,26 +1337,13 @@ static int __init sdma_probe(struct platform_device *pdev)
                goto err_init;
        }
 
-       dev_info(&pdev->dev, "initialized (firmware %d.%d)\n",
-                       header->version_major,
-                       header->version_minor);
-
-       /* request channel 0. This is an internal control channel
-        * to the SDMA engine and not available to clients.
-        */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       dma_request_channel(mask, NULL, NULL);
-
-       release_firmware(fw);
+       dev_info(sdma->dev, "initialized\n");
 
        return 0;
 
 err_init:
        kfree(sdma->script_addrs);
-err_firmware:
-       release_firmware(fw);
-err_cputype:
+err_alloc:
        free_irq(irq, sdma);
 err_request_irq:
        iounmap(sdma->regs);
@@ -1366,7 +1354,7 @@ err_clk:
 err_request_region:
 err_irq:
        kfree(sdma);
-       return 0;
+       return ret;
 }
 
 static int __exit sdma_remove(struct platform_device *pdev)