static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { struct sdma_channel *sdmac = to_sdma_chan(chan); struct dma_slave_config *dmaengine_cfg = (void *)arg; switch (cmd) { case DMA_TERMINATE_ALL: sdma_disable_channel(sdmac); return 0; case DMA_SLAVE_CONFIG: if (dmaengine_cfg->direction == DMA_FROM_DEVICE) { sdmac->per_address = dmaengine_cfg->src_addr; sdmac->watermark_level = dmaengine_cfg->src_maxburst; sdmac->word_size = dmaengine_cfg->src_addr_width; } else { sdmac->per_address = dmaengine_cfg->dst_addr; sdmac->watermark_level = dmaengine_cfg->dst_maxburst; sdmac->word_size = dmaengine_cfg->dst_addr_width; } return sdma_config_channel(sdmac); default: return -ENOSYS; } return -EINVAL; }
static int setup_fpga_interface(struct sdma_engine *sdma) { const int channel = 1; struct sdma_channel *sdmac = &sdma->channel[channel]; const u32 sdma_code[24] = { 0x6c20672b, 0x07647d02, 0x04007cfa, 0x612b622b, 0x662b0762, 0x7d0e6900, 0x6d0406da, 0x7d056e18, 0x000002a6, 0x0e087cf8, 0x6a186c14, 0x6c2b7ce8, 0x7de7632b, 0x6904008f, 0x38037802, 0x6b290312, 0x4a007d09, 0x6d0006da, 0x7d056e18, 0x000002a6, 0x0e087cf8, 0x6a180763, 0x7ce80300, 0x7de60000, }; const int origin = 0xe00; /* In data space terms (32 bits/address) */ struct sdma_context_data *context = sdma->context; int ret; ret = eim_init(); if (ret) { printk(KERN_ERR THIS "Failed to initialize EIM bus\n"); return ret; } sdma_write_datamem(sdma, (void *) sdma_code, sizeof(sdma_code), origin); ret = sdma_request_channel(sdmac); if (ret) { printk(KERN_ERR "Failed to request channel\n"); return ret; } sdma_disable_channel(sdmac); /* Don't let events run yet: */ sdma_config_ownership(sdmac, true, true, false); memset(context, 0, sizeof(*context)); context->channel_state.pc = origin * 2; /* In program space addressing */ context->gReg[4] = MX51_CS2_BASE_ADDR + 0x80; /* Request region */ context->gReg[5] = MX51_CS2_BASE_ADDR + 0x8000; /* Data region */ ret = sdma_write_datamem(sdma, (void *) context, sizeof(*context), 0x800 + (sizeof(*context) / 4) * channel); if (ret) { printk(KERN_ERR "Failed to load context\n"); return ret; } sdmac->desc.callback = sdma_irq_callback; sdmac->desc.callback_param = NULL; xillybus_sdmac = sdmac; return 0; /* Success! */ }
static int sdma_config_channel(struct sdma_channel *sdmac) { int ret; sdma_disable_channel(sdmac); sdmac->event_mask0 = 0; sdmac->event_mask1 = 0; sdmac->shp_addr = 0; sdmac->per_addr = 0; if (sdmac->event_id0) { if (sdmac->event_id0 > 32) return -EINVAL; sdma_event_enable(sdmac, sdmac->event_id0); } switch (sdmac->peripheral_type) { case IMX_DMATYPE_DSP: sdma_config_ownership(sdmac, false, true, true); break; case IMX_DMATYPE_MEMORY: sdma_config_ownership(sdmac, false, true, false); break; default: sdma_config_ownership(sdmac, true, true, false); break; } sdma_get_pc(sdmac, sdmac->peripheral_type); if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { /* Handle multiple event channels differently */ if (sdmac->event_id1) { sdmac->event_mask1 = 1 << (sdmac->event_id1 % 32); if (sdmac->event_id1 > 31) sdmac->watermark_level |= 1 << 31; sdmac->event_mask0 = 1 << (sdmac->event_id0 % 32); if (sdmac->event_id0 > 31) sdmac->watermark_level |= 1 << 30; } else { sdmac->event_mask0 = 1 << sdmac->event_id0; sdmac->event_mask1 = 1 << (sdmac->event_id0 - 32); } /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; /* Address */ sdmac->shp_addr = sdmac->per_address; } else { sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ } ret = sdma_load_context(sdmac); return ret; }
static void sdma_free_chan_resources(struct dma_chan *chan) { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; sdma_disable_channel(sdmac); if (sdmac->event_id0) sdma_event_disable(sdmac, sdmac->event_id0); if (sdmac->event_id1) sdma_event_disable(sdmac, sdmac->event_id1); sdmac->event_id0 = 0; sdmac->event_id1 = 0; sdma_set_channel_priority(sdmac, 0); dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); clk_disable(sdma->clk); }
static int sdma_config_channel(struct sdma_channel *sdmac) { int ret; sdma_disable_channel(sdmac); sdmac->event_mask0 = 0; sdmac->event_mask1 = 0; sdmac->shp_addr = 0; sdmac->per_addr = 0; if (sdmac->event_id0) sdma_event_enable(sdmac, sdmac->event_id0); if (sdmac->event_id1) sdma_event_enable(sdmac, sdmac->event_id1); switch (sdmac->peripheral_type) { case IMX_DMATYPE_DSP: sdma_config_ownership(sdmac, false, true, true); break; case IMX_DMATYPE_MEMORY: sdma_config_ownership(sdmac, false, true, false); break; default: sdma_config_ownership(sdmac, true, true, false); break; } sdma_get_pc(sdmac, sdmac->peripheral_type); if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { /* Handle multiple event channels differently */ if (sdmac->event_id1) { if (sdmac->event_id0 > 31) { sdmac->watermark_level |= 1 << 28; sdmac->event_mask0 |= 0; sdmac->event_mask1 |= 1 << ((sdmac->event_id0)%32); } else { sdmac->event_mask0 |= 1 << ((sdmac->event_id0)%32); sdmac->event_mask1 |= 0; } if (sdmac->event_id1 > 31) { sdmac->watermark_level |= 1 << 29; sdmac->event_mask0 |= 0; sdmac->event_mask1 |= 1 << ((sdmac->event_id1)%32); } else { sdmac->event_mask0 |= 1 << ((sdmac->event_id1)%32); sdmac->event_mask1 |= 0; } sdmac->watermark_level |= (unsigned int)(3<<11); sdmac->watermark_level |= (unsigned int)(1<<31); sdmac->watermark_level |= (unsigned int)(2<<24); } else { if (sdmac->event_id0 > 31) { sdmac->event_mask0 = 0; sdmac->event_mask1 = 1 << ((sdmac->event_id0)%32); } else { sdmac->event_mask0 = 1 << ((sdmac->event_id0)%32); sdmac->event_mask1 = 0; } } /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; /* Address */ switch (sdmac->direction) { case DMA_DEV_TO_DEV: sdmac->per_addr = sdmac->per_address; sdmac->shp_addr = sdmac->per_address2; break; default: sdmac->shp_addr = sdmac->per_address; break; } } else { sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ } ret = sdma_load_context(sdmac); return ret; }
void sdma_xillybus_remove(void) { sdma_event_disable(xillybus_sdmac, 15); /* Connect to channel 15 */ sdma_disable_channel(xillybus_sdmac); xillybus_handler = NULL; }