void cy_as_intr_service_interrupt(cy_as_hal_device_tag tag) { uint16_t v; cy_as_device *dev_p; dev_p = cy_as_device_find_from_tag(tag); /* * only power management interrupts can occur before the * antioch API setup is complete. if this is a PM interrupt * handle it here; otherwise output a warning message. */ if (dev_p == 0) { v = cy_as_hal_read_register(tag, CY_AS_MEM_P0_INTR_REG); if (v == CY_AS_MEM_P0_INTR_REG_PMINT) { /* Read the PWR_MAGT_STAT register * to clear this interrupt. */ v = cy_as_hal_read_register(tag, CY_AS_MEM_PWR_MAGT_STAT); } else cy_as_hal_print_message("stray antioch " "interrupt detected" ", tag not associated " "with any created device."); return; } /* Make sure we got a valid object from CyAsDeviceFindFromTag */ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE); v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_INTR_REG); if (v & CY_AS_MEM_P0_INTR_REG_MCUINT) cy_as_mcu_interrupt_handler(dev_p); if (v & CY_AS_MEM_P0_INTR_REG_PMINT) cy_as_power_management_interrupt_handler(dev_p); if (v & CY_AS_MEM_P0_INTR_REG_PLLLOCKINT) cy_as_pll_lock_loss_interrupt_handler(dev_p); /* If the interrupt module is not running, no mailbox * interrupts are expected from the west bridge. */ if (cy_as_device_is_intr_running(dev_p) == 0) return; if (v & CY_AS_MEM_P0_INTR_REG_MBINT) cy_as_mail_box_interrupt_handler(dev_p); }
void cy_as_hal_dump_reg(cy_as_hal_device_tag tag) { u16 data16; int i; int retval = 0; printk(KERN_ERR "=======================================\n"); printk(KERN_ERR "======== Astoria REG Dump =========\n"); for ( i=0 ; i<256 ; i++ ) { data16 = cy_as_hal_read_register(tag, i); printk(KERN_ERR "%4.4x ", data16); if( i%8 == 7 ) printk(KERN_ERR "\n"); } printk(KERN_ERR "=======================================\n\n"); printk(KERN_ERR "======== Astoria REG Test =========\n"); cy_as_hal_write_register(tag, CY_AS_MEM_MCU_MAILBOX1, 0xAAAA); cy_as_hal_write_register(tag, CY_AS_MEM_MCU_MAILBOX2, 0x5555); cy_as_hal_write_register(tag, CY_AS_MEM_MCU_MAILBOX3, 0xB4C3); data16 = cy_as_hal_read_register(tag, CY_AS_MEM_MCU_MAILBOX1); if( data16 != 0xAAAA) { printk(KERN_ERR "REG Test Error in CY_AS_MEM_MCU_MAILBOX1 - %4.4x\n", data16); retval = 1; } data16 = cy_as_hal_read_register(tag, CY_AS_MEM_MCU_MAILBOX2); if( data16 != 0x5555) { printk(KERN_ERR "REG Test Error in CY_AS_MEM_MCU_MAILBOX2 - %4.4x\n", data16); retval = 1; } data16 = cy_as_hal_read_register(tag, CY_AS_MEM_MCU_MAILBOX3); if( data16 != 0xB4C3) { printk(KERN_ERR "REG Test Error in CY_AS_MEM_MCU_MAILBOX3 - %4.4x\n", data16); retval = 1; } if( retval) printk(KERN_ERR "REG Test fail !!!!!\n"); else printk(KERN_ERR "REG Test success !!!!!\n"); printk(KERN_ERR "=======================================\n\n"); }
/* * Set the DRQ mask register for the given endpoint number. If state is * CyTrue, the DRQ interrupt for the given endpoint is enabled, otherwise * it is disabled. */ static void cy_as_dma_set_drq(cy_as_device *dev_p, cy_as_end_point_number_t ep, cy_bool state) { uint16_t mask ; uint16_t v ; uint32_t intval ; /* * there are not DRQ register bits for EP0 and EP1 */ if (ep == 0 || ep == 1) return ; /* * disable interrupts while we do this to be sure the state of the * DRQ mask register is always well defined. */ intval = cy_as_hal_disable_interrupts() ; /* * set the DRQ bit to the given state for the ep given */ mask = (1 << ep) ; v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_DRQ_MASK) ; if (state) v |= mask ; else v &= ~mask ; cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_DRQ_MASK, v) ; cy_as_hal_enable_interrupts(intval) ; }
void cy_as_pll_lock_loss_interrupt_handler(cy_as_device *dev_p) { uint16_t v; v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PLL_LOCK_LOSS_STAT); v = v; }
void cy_as_power_management_interrupt_handler(cy_as_device *dev_p) { uint16_t v; v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PWR_MAGT_STAT); v = v; }
void hal_reset(cy_as_hal_device_tag tag) { cy_as_hal_print_message("<1> send soft hard rst: " "MEM_RST_CTRL_REG_HARD...\n"); cy_as_hal_write_register(tag, CY_AS_MEM_RST_CTRL_REG, CY_AS_MEM_RST_CTRL_REG_HARD); mdelay(60); cy_as_hal_print_message("<1> after RST: si_rev_REG:%x, " "PNANDCFG_reg:%x\n", cy_as_hal_read_register(tag, CY_AS_MEM_CM_WB_CFG_ID), cy_as_hal_read_register(tag, CY_AS_MEM_PNAND_CFG) ); /* set it to LBD */ cy_as_hal_write_register(tag, CY_AS_MEM_PNAND_CFG, PNAND_REG_CFG_INIT_VAL); }
void cy_as_mcu_interrupt_handler(cy_as_device *dev_p) { /* Read and clear the interrupt. */ uint16_t v; v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_MCU_STAT); v = v; }
/* * Wait for all entries in the DMA queue associated * the given endpoint to be drained. This function * will not return until all the DMA data has been * transferred. */ cy_as_return_status_t cy_as_dma_drain_queue(cy_as_device *dev_p, cy_as_end_point_number_t ep, cy_bool kickstart) { cy_as_dma_end_point *ep_p ; int loopcount = 200 ; uint32_t mask ; /* * make sure the endpoint is valid */ if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0])) return CY_AS_ERROR_INVALID_ENDPOINT ; /* Get the endpoint pointer based on the endpoint number */ ep_p = CY_AS_NUM_EP(dev_p, ep) ; /* * if the endpoint is empty of traffic, we return * with success immediately */ mask = cy_as_hal_disable_interrupts() ; if (ep_p->queue_p == 0) { cy_as_hal_enable_interrupts(mask) ; return CY_AS_ERROR_SUCCESS ; } else { /* * add 10 seconds to the time out value for each 64 KB segment * of data to be transferred. */ if (ep_p->queue_p->size > 0x10000) loopcount += ((ep_p->queue_p->size / 0x10000) * 100) ; } cy_as_hal_enable_interrupts(mask) ; /* If we are already sleeping on this endpoint, it is an error */ if (cy_as_dma_end_point_is_sleeping(ep_p)) return CY_AS_ERROR_NESTED_SLEEP ; /* * we disable the endpoint while the queue drains to * prevent any additional requests from being queued while we are waiting */ cy_as_dma_enable_end_point(dev_p, ep, cy_false, cy_as_direction_dont_change) ; if (kickstart) { /* * now, kick start the DMA if necessary */ cy_as_dma_kick_start(dev_p, ep) ; } /* * check one last time before we begin sleeping to see if the * queue is drained. */ if (ep_p->queue_p == 0) { cy_as_dma_enable_end_point(dev_p, ep, cy_true, cy_as_direction_dont_change) ; return CY_AS_ERROR_SUCCESS ; } while (loopcount-- > 0) { /* * sleep for 10 ms maximum (per loop) while * waiting for the transfer to complete. */ cy_as_dma_end_point_set_sleep_state(ep_p) ; cy_as_hal_sleep_on(&ep_p->channel, 10) ; /* If we timed out, the sleep bit will still be set */ cy_as_dma_end_point_set_wake_state(ep_p) ; /* Check the queue to see if is drained */ if (ep_p->queue_p == 0) { /* * clear the endpoint running and in transit flags * for the endpoint, now that its DMA queue is empty. */ cy_as_dma_end_point_clear_in_transit(ep_p) ; cy_as_dma_end_point_set_stopped(ep_p) ; cy_as_dma_enable_end_point(dev_p, ep, cy_true, cy_as_direction_dont_change) ; return CY_AS_ERROR_SUCCESS ; } } printk(KERN_ERR"cyasdevice:timeout 0xA0 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0xA0)); printk(KERN_ERR"cyasdevice:timeout 0xA1 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0xA1)); printk(KERN_ERR"cyasdevice:timeout 0xA2 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0xA2)); printk(KERN_ERR"cyasdevice:timeout 0x90 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0x90)); printk(KERN_ERR"cyasdevice:timeout 0x91 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0x91)); /* * the DMA operation that has timed out can be cancelled, so that later * operations on this queue can proceed. */ cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_TIMEOUT) ; cy_as_dma_enable_end_point(dev_p, ep, cy_true, cy_as_direction_dont_change) ; return CY_AS_ERROR_TIMEOUT ; }
/* * Astoria DMA read request, APP_CPU reads from WB ep buffer */ static void cy_service_e_p_dma_read_request( cy_as_omap_dev_kernel *dev_p, uint8_t ep) { cy_as_hal_device_tag tag = (cy_as_hal_device_tag)dev_p ; uint16_t v, i, size; uint16_t *dptr; uint16_t ep_dma_reg = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2; register void *read_addr ; register uint16_t a,b,c,d,e,f,g,h ; /* * get the XFER size frtom WB eP DMA REGISTER */ v = cy_as_hal_read_register(tag, ep_dma_reg); /* * amount of data in EP buff in bytes */ size = v & CY_AS_MEM_P0_E_pn_DMA_REG_COUNT_MASK; /* * memory pointer for this DMA packet xfer (sub_segment) */ dptr = (uint16_t *) end_points[ep].data_p; read_addr = dev_p->m_vma_addr_base + CYAS_DEV_CALC_EP_ADDR(ep) ; cy_as_hal_assert(size != 0); if (size) { /* * Now, read the data from the device */ for(i = size/16 ; i > 0 ; i--) { a = (unsigned short) readw (read_addr) ; b = (unsigned short) readw (read_addr) ; c = (unsigned short) readw (read_addr) ; d = (unsigned short) readw (read_addr) ; e = (unsigned short) readw (read_addr) ; f = (unsigned short) readw (read_addr) ; g = (unsigned short) readw (read_addr) ; h = (unsigned short) readw (read_addr) ; *dptr++ = a ; *dptr++ = b ; *dptr++ = c ; *dptr++ = d ; *dptr++ = e ; *dptr++ = f ; *dptr++ = g ; *dptr++ = h ; } switch ((size & 0xF)/2) { case 7: *dptr = (unsigned short) readw(read_addr) ; dptr++ ; case 6: *dptr = (unsigned short) readw(read_addr) ; dptr++ ; case 5: *dptr = (unsigned short) readw(read_addr) ; dptr++ ; case 4: *dptr = (unsigned short) readw(read_addr) ; dptr++ ; case 3: *dptr = (unsigned short) readw(read_addr) ; dptr++ ; case 2: *dptr = (unsigned short) readw(read_addr) ; dptr++ ; case 1: *dptr = (unsigned short) readw(read_addr) ; dptr++ ; break ; } if (size & 1) { /* Odd sized packet */ uint16_t d = (unsigned short) readw (read_addr) ; *((uint8_t *)dptr) = (d & 0xff) ; } } /* * clear DMAVALID bit indicating that the data has been read */ cy_as_hal_write_register(tag, ep_dma_reg, 0) ; end_points[ep].seg_xfer_cnt += size; end_points[ep].req_xfer_cnt += size; /* * pre-advance data pointer (if it's outside sg * list it will be reset anyway */ end_points[ep].data_p += size; if (prep_for_next_xfer(tag, ep)) { /* * we have more data to read in this request, * setup next dma packet due tell WB how much * data we are going to xfer next */ v = end_points[ep].dma_xfer_sz/*HAL_DMA_PKT_SZ*/ | CY_AS_MEM_P0_E_pn_DMA_REG_DMAVAL ; cy_as_hal_write_register(tag, ep_dma_reg, v); } else { end_points[ep].pending = cy_false ; end_points[ep].type = cy_as_hal_none ; end_points[ep].buffer_valid = cy_false ; /* * notify the API that we are done with rq on this EP */ if (callback) { DBGPRN("<1>trigg rd_dma completion cb: xfer_sz:%d\n", end_points[ep].req_xfer_cnt); callback(tag, ep, end_points[ep].req_xfer_cnt, CY_AS_ERROR_SUCCESS); } } }
/* * west bridge astoria ISR (Interrupt handler) */ static irqreturn_t cy_astoria_int_handler(int irq, void *dev_id, struct pt_regs *regs) { cy_as_omap_dev_kernel *dev_p; uint16_t read_val = 0 ; uint16_t mask_val = 0 ; /* * debug stuff, counts number of loops per one intr trigger */ uint16_t drq_loop_cnt = 0; uint8_t irq_pin; /* * flags to watch */ const uint16_t sentinel = (CY_AS_MEM_P0_INTR_REG_MCUINT | CY_AS_MEM_P0_INTR_REG_MBINT | CY_AS_MEM_P0_INTR_REG_PMINT | CY_AS_MEM_P0_INTR_REG_PLLLOCKINT); /* * sample IRQ pin level (just for statistics) */ irq_pin = __gpio_get_value(AST_INT); /* * this one just for debugging */ intr_sequence_num++ ; /* * astoria device handle */ dev_p = dev_id; /* * read Astoria intr register */ read_val = cy_as_hal_read_register((cy_as_hal_device_tag)dev_p, CY_AS_MEM_P0_INTR_REG) ; /* * save current mask value */ mask_val = cy_as_hal_read_register((cy_as_hal_device_tag)dev_p, CY_AS_MEM_P0_INT_MASK_REG) ; DBGPRN("<1>HAL__intr__enter:_seq:%d, P0_INTR_REG:%x\n", intr_sequence_num, read_val); /* * Disable WB interrupt signal generation while we are in ISR */ cy_as_hal_write_register((cy_as_hal_device_tag)dev_p, CY_AS_MEM_P0_INT_MASK_REG, 0x0000) ; /* * this is a DRQ Interrupt */ if (read_val & CY_AS_MEM_P0_INTR_REG_DRQINT) { do { /* * handle DRQ interrupt */ drq_loop_cnt++; cy_handle_d_r_q_interrupt(dev_p) ; /* * spending to much time in ISR may impact * average system performance */ if (drq_loop_cnt >= MAX_DRQ_LOOPS_IN_ISR) break; /* * Keep processing if there is another DRQ int flag */ } while (cy_as_hal_read_register((cy_as_hal_device_tag)dev_p, CY_AS_MEM_P0_INTR_REG) & CY_AS_MEM_P0_INTR_REG_DRQINT); } if (read_val & sentinel) cy_as_intr_service_interrupt((cy_as_hal_device_tag)dev_p) ; DBGPRN("<1>_hal:_intr__exit seq:%d, mask=%4.4x," "int_pin:%d DRQ_jobs:%d\n", intr_sequence_num, mask_val, irq_pin, drq_loop_cnt); /* * re-enable WB hw interrupts */ cy_as_hal_write_register((cy_as_hal_device_tag)dev_p, CY_AS_MEM_P0_INT_MASK_REG, mask_val) ; return IRQ_HANDLED ; }
/* * init OMAP h/w resources */ int cy_as_hal_omap_cram_start(const char *pgm, cy_as_hal_device_tag *tag, cy_bool debug) { cy_as_omap_dev_kernel *dev_p ; int i; u16 data16[4]; uint32_t err = 0; /* No debug mode support through argument as of now */ (void)debug; have_irq = false; /* * Initialize the HAL level endpoint DMA data. */ for (i = 0 ; i < sizeof(end_points)/sizeof(end_points[0]) ; i++) { end_points[i].data_p = 0 ; end_points[i].pending = cy_false ; end_points[i].size = 0 ; /* No debug mode support through argument as of now */ (void)debug; end_points[i].type = cy_as_hal_none ; end_points[i].sg_list_enabled = cy_false; /* * by default the DMA transfers to/from the E_ps don't * use sg_list that implies that the upper devices like * blockdevice have to enable it for the E_ps in their * initialization code */ } /* allocate memory for OMAP HAL*/ dev_p = (cy_as_omap_dev_kernel *)cy_as_hal_alloc( sizeof(cy_as_omap_dev_kernel)) ; if (dev_p == 0) { cy_as_hal_print_message("out of memory allocating OMAP" "device structure\n") ; return 0 ; } dev_p->m_sig = CY_AS_OMAP_CRAM_HAL_SIG; /* initialize OMAP hardware and StartOMAPKernelall gpio pins */ err = cy_as_hal_processor_hw_init(dev_p); if(err) goto bus_acc_error; /* * Now perform a hard reset of the device to have * the new settings take effect */ __gpio_set_value(AST_WAKEUP, 1); /* * do Astoria h/w reset */ DBGPRN(KERN_INFO"-_-_pulse -> westbridge RST pin\n"); /* * NEGATIVE PULSE on RST pin */ __gpio_set_value(AST_RESET, 0); mdelay(1); __gpio_set_value(AST_RESET, 1); mdelay(50); /* * NOTE: if you want to capture bus activity on the LA, * don't use printks in between the activities you want to capture. * prinks may take milliseconds, and the data of interest * will fall outside the LA capture window/buffer */ cy_as_hal_dump_reg((cy_as_hal_device_tag)dev_p); data16[0] = cy_as_hal_read_register((cy_as_hal_device_tag)dev_p, CY_AS_MEM_CM_WB_CFG_ID); if ( (data16[0]&0xA100 != 0xA100) || (data16[0]&0xA200 != 0xA200)) { /* * astoria device is not found */ printk(KERN_ERR "ERROR: astoria device is not found, " "CY_AS_MEM_CM_WB_CFG_ID %4.4x", data16[0]); goto bus_acc_error; } cy_as_hal_print_message(KERN_INFO" register access test:" "\n CY_AS_MEM_CM_WB_CFG_ID:%4.4x\n" "after cfg_wr:%4.4x\n\n", data16[0], data16[1]); dev_p->thread_flag = 1 ; spin_lock_init(&int_lock) ; dev_p->m_next_p = m_omap_list_p ; m_omap_list_p = dev_p ; *tag = dev_p; cy_as_hal_configure_interrupts((void *)dev_p); cy_as_hal_print_message(KERN_INFO"OMAP3430__hal started tag:%p" ", kernel HZ:%d\n", dev_p, HZ); /* *make processor to storage endpoints SG assisted by default */ cy_as_hal_set_ep_dma_mode(4, true); cy_as_hal_set_ep_dma_mode(8, true); return 1 ; /* * there's been a NAND bus access error or * astoria device is not connected */ bus_acc_error: /* * at this point hal tag hasn't been set yet * so the device will not call omap_stop */ cy_as_hal_omap_hardware_deinit(dev_p); cy_as_hal_free(dev_p) ; return 0; }
/* * HANDLE DRQINT from Astoria (called in AS_Intr context */ static void cy_handle_d_r_q_interrupt(cy_as_omap_dev_kernel *dev_p) { uint16_t v ; static uint8_t service_ep = 2 ; /* * We've got DRQ INT, read DRQ STATUS Register */ v = cy_as_hal_read_register((cy_as_hal_device_tag)dev_p, CY_AS_MEM_P0_DRQ) ; if (v == 0) { #ifndef WESTBRIDGE_NDEBUG cy_as_hal_print_message("stray DRQ interrupt detected\n") ; #endif return; } /* * Now, pick a given DMA request to handle, for now, we just * go round robin. Each bit position in the service_mask * represents an endpoint from EP2 to EP15. We rotate through * each of the endpoints to find one that needs to be serviced. */ while ((v & (1 << service_ep)) == 0) { if (service_ep == 15) service_ep = 2 ; else service_ep++ ; } if (end_points[service_ep].type == cy_as_hal_write) { /* * handle DMA WRITE REQUEST: app_cpu will * write data into astoria EP buffer */ cy_service_e_p_dma_write_request(dev_p, service_ep) ; } else if (end_points[service_ep].type == cy_as_hal_read) { /* * handle DMA READ REQUEST: cpu will * read EP buffer from Astoria */ cy_service_e_p_dma_read_request(dev_p, service_ep) ; } #ifndef WESTBRIDGE_NDEBUG else cy_as_hal_print_message("cyashalomap:interrupt," " w/o pending DMA job," "-check DRQ_MASK logic\n") ; #endif /* * Now bump the EP ahead, so other endpoints get * a shot before the one we just serviced */ if (end_points[service_ep].type == cy_as_hal_none) { if (service_ep == 15) service_ep = 2 ; else service_ep++ ; } }