/* Commit and/or discard all DMA descriptors and buffers pointed by them, * handle circular lists. At the same time, convert virtual pointers to * real ones */ static void dma_commit_and_discard(unsigned chan, struct apb_dma_command_t *cmd) { /* We handle circular descriptors by using unused bits: * bits 8-11 are not used by the hardware so we first go through the whole * list and mark them all a special value at the same time we commit buffers * and then we go through the list another time to clear the mark and * commit the descriptors */ struct apb_dma_command_t *cur = cmd; while((cur->cmd & HW_APB_CHx_CMD__UNUSED_BM) != HW_APB_CHx_CMD__UNUSED_MAGIC) { cur->cmd = (cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM) | HW_APB_CHx_CMD__UNUSED_MAGIC; int op = cur->cmd & HW_APB_CHx_CMD__COMMAND_BM; int sz = __XTRACT_EX(cur->cmd, HW_APB_CHx_CMD__XFER_COUNT); /* device > host: discard */ if(op == HW_APB_CHx_CMD__COMMAND__WRITE) discard_dcache_range(cur->buffer, sz); /* host > device: commit and discard */ else if(op == HW_APB_CHx_CMD__COMMAND__READ) commit_discard_dcache_range(cur->buffer, sz); if((uint32_t)cur->buffer % CACHEALIGN_SIZE) apb_nr_unaligned[chan]++; /* Virtual to physical buffer pointer conversion */ cur->buffer = PHYSICAL_ADDR(cur->buffer); /* chain ? */ if(cur->cmd & HW_APB_CHx_CMD__CHAIN) cur = cur->next; else break; } cur = cmd; while((cur->cmd & HW_APB_CHx_CMD__UNUSED_BM) != 0) { cur->cmd = cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM; int sz = __XTRACT_EX(cur->cmd, HW_APB_CHx_CMD__CMDWORDS) * sizeof(uint32_t); /* commit descriptor and discard descriptor */ /* chain ? */ if(cur->cmd & HW_APB_CHx_CMD__CHAIN) { struct apb_dma_command_t *next = cur->next; cur->next = PHYSICAL_ADDR(cur->next); commit_dcache_range(cur, sizeof(struct apb_dma_command_t) + sz); cur = next; } else { commit_dcache_range(cur, sizeof(struct apb_dma_command_t) + sz); break; } } }
static enum imx233_dcp_error_t imx233_dcp_job(int ch) { /* if IRQs are not enabled, don't enable channel interrupt and do some polling */ bool irq_enabled = irq_enabled(); /* enable channel, clear interrupt, enable interrupt */ imx233_icoll_enable_interrupt(INT_SRC_DCP, true); if(irq_enabled) __REG_SET(HW_DCP_CTRL) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch); __REG_CLR(HW_DCP_STAT) = HW_DCP_STAT__IRQ(ch); __REG_SET(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch); /* write back packet */ commit_discard_dcache_range(&channel_packet[ch], sizeof(struct imx233_dcp_packet_t)); /* write 1 to semaphore to run job */ HW_DCP_CHxCMDPTR(ch) = (uint32_t)PHYSICAL_ADDR(&channel_packet[ch]); HW_DCP_CHxSEMA(ch) = 1; /* wait completion */ if(irq_enabled) semaphore_wait(&channel_sema[ch], TIMEOUT_BLOCK); else while(__XTRACT_EX(HW_DCP_CHxSEMA(ch), HW_DCP_CHxSEMA__VALUE)) udelay(10); /* disable channel and interrupt */ __REG_CLR(HW_DCP_CTRL) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch); __REG_CLR(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch); /* read status */ return get_error_status(ch); }
int lradc_read_channel(int channel) { /* check the channel index */ if ((channel < 0) || (channel > MAX_USER_LRADC)) { return -1; } return __XTRACT_EX(HW_LRADC_CHx(channel), HW_LRADC_CHx__VALUE); }
int dma_wait_completion(unsigned chan, unsigned tmo) { tmo += current_tick; volatile uint32_t *sema; if(APB_IS_APBX_CHANNEL(chan)) sema = &HW_APBX_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); else sema = &HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); while(*sema & HW_APB_CHx_SEMA__PHORE_BM && !TIME_AFTER(current_tick, tmo)) udelay(10); return __XTRACT_EX(*sema, HW_APB_CHx_SEMA__PHORE); }
struct imx233_dcp_info_t imx233_dcp_get_info(unsigned flags) { struct imx233_dcp_info_t info; memset(&info, 0, sizeof(info)); if(flags & DCP_INFO_CAPABILITIES) { info.has_crypto = HW_DCP_CTRL & HW_DCP_CTRL__PRESENT_CRYPTO; info.has_csc = HW_DCP_CTRL & HW_DCP_CTRL__PRESENT_CSC; info.num_keys = __XTRACT(HW_DCP_CAPABILITY0, NUM_KEYS); info.num_channels = __XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS); info.ciphers = __XTRACT(HW_DCP_CAPABILITY1, CIPHER_ALGORITHMS); info.hashs = __XTRACT(HW_DCP_CAPABILITY1, HASH_ALGORITHMS); } if(flags & DCP_INFO_GLOBAL_STATE) { info.otp_key_ready = HW_DCP_STAT & HW_DCP_STAT__OTP_KEY_READY; info.context_switching = HW_DCP_CTRL & HW_DCP_CTRL__ENABLE_CONTEXT_SWITCHING; info.context_caching = HW_DCP_CTRL & HW_DCP_CTRL__ENABLE_CONTEXT_CACHING; info.gather_writes = HW_DCP_CTRL & HW_DCP_CTRL__GATHER_RESIDUAL_WRITES; info.ch0_merged = HW_DCP_CHANNELCTRL & HW_DCP_CHANNELCTRL__CH0_IRQ_MERGED; } if(flags & DCP_INFO_CHANNELS) { for(int i = 0; i < HW_DCP_NUM_CHANNELS; i++) { info.channel[i].irq_en = HW_DCP_CTRL & HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(i); info.channel[i].irq = HW_DCP_STAT & HW_DCP_STAT__IRQ(i); info.channel[i].ready = HW_DCP_STAT & HW_DCP_STAT__READY_CHANNELS(i); info.channel[i].high_priority = HW_DCP_CHANNELCTRL & HW_DCP_CHANNELCTRL__HIGH_PRIORITY_CHANNEL(i); info.channel[i].enable = HW_DCP_CHANNELCTRL & HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(i); info.channel[i].sema = __XTRACT_EX(HW_DCP_CHxSEMA(i), HW_DCP_CHxSEMA__VALUE); info.channel[i].cmdptr = HW_DCP_CHxCMDPTR(i); info.channel[i].acquired = arbiter_acquired(&channel_arbiter, i); } } if(flags & DCP_INFO_CSC) { info.csc.irq_en = HW_DCP_CTRL & HW_DCP_CTRL__CSC_INTERRUPT_ENABLE; info.csc.irq = HW_DCP_STAT & HW_DCP_STAT__CSCIRQ; info.csc.priority = __XTRACT(HW_DCP_CHANNELCTRL, CSC_PRIORITY); info.csc.enable = HW_DCP_CSCCTRL0 & HW_DCP_CSCCTRL0__ENABLE; } return info; }
static enum imx233_dcp_error_t get_error_status(int ch) { uint32_t stat = channel_packet[ch].status; if(stat & HW_DCP_STATUS__ERROR_SETUP) return DCP_ERROR_SETUP; if(stat & HW_DCP_STATUS__ERROR_PACKET) return DCP_ERROR_PACKET; if(stat & HW_DCP_STATUS__ERROR_SRC) return DCP_ERROR_SRC; if(stat & HW_DCP_STATUS__ERROR_DST) return DCP_ERROR_DST; switch(__XTRACT_EX(stat, HW_DCP_STATUS__ERROR_CODE)) { case 0: return DCP_SUCCESS; case 1: return DCP_ERROR_CHAIN_IS_0; case 2: return DCP_ERROR_NO_CHAIN; case 3: return DCP_ERROR_CONTEXT; case 4: return DCP_ERROR_PAYLOAD; case 5: return DCP_ERROR_MODE; default: return DCP_ERROR; } }
int imx233_lradc_read_channel(int channel) { return __XTRACT_EX(HW_LRADC_CHx(channel), HW_LRADC_CHx__VALUE); }