void lcd_init_device(void) { semaphore_init(&g_wait_sema, 1, 0); /* I'm not really sure this pin is related to power, it does not seem to do anything */ imx233_pinctrl_acquire(1, 8, "lcd_power"); imx233_pinctrl_acquire(1, 9, "lcd_spi_sdo"); imx233_pinctrl_acquire(1, 10, "lcd_spi_scl"); imx233_pinctrl_acquire(1, 11, "lcd_spi_cs"); imx233_pinctrl_set_function(1, 9, PINCTRL_FUNCTION_GPIO); imx233_pinctrl_set_function(1, 10, PINCTRL_FUNCTION_GPIO); imx233_pinctrl_set_function(1, 11, PINCTRL_FUNCTION_GPIO); imx233_pinctrl_set_function(1, 8, PINCTRL_FUNCTION_GPIO); imx233_pinctrl_enable_gpio(1, 8, true); /** lcd is 320x240, data bus is 8-bit, depth is 24-bit so we need 3clk/pix * by running PIX clock at 24MHz we can sustain ~100 fps */ imx233_clkctrl_enable(CLK_PIX, false); imx233_clkctrl_set_div(CLK_PIX, 2); imx233_clkctrl_set_bypass(CLK_PIX, true); /* use XTAL */ imx233_clkctrl_enable(CLK_PIX, true); imx233_lcdif_init(); imx233_lcdif_setup_dotclk_pins(8, false); imx233_lcdif_set_word_length(8); imx233_lcdif_set_underflow_cb(&lcd_underflow); imx233_lcdif_enable_underflow_irq(true); imx233_dma_clkgate_channel(APB_LCDIF, true); imx233_dma_reset_channel(APB_LCDIF); /** Datasheet states: * 257H >= VBP >= 3H, VBP > VLW, VFP >= 1H * 1533clk >= HBP >= 24clk, HBP > HLW, HFP >= 4clk * * Take VLW=1H, VBP=3H, VFP=1H, HLW=8, HBP=24, HFP=4 * Take 3clk/pix because we send 24-bit/pix with 8-bit data bus * Keep consistent with register setting in lcd_init_seq */ imx233_lcdif_setup_dotclk_ex(/*v_pulse_width*/1, /*v_back_porch*/3, /*v_front_porch*/1, /*h_pulse_width*/8, /*h_back_porch*/24, /*h_front_porch*/4, LCD_WIDTH, LCD_HEIGHT, /*clk_per_pix*/3, /*enable_present*/false); imx233_lcdif_set_byte_packing_format(0xf); imx233_lcdif_enable_sync_signals(true); // we need frame signals during init // setup dma unsigned size = IMX233_FRAMEBUFFER_SIZE; uint8_t *frame_p = FRAME; for(int i = 0; i < NR_CMDS; i++) { unsigned xfer = MIN(IMX233_MAX_SINGLE_DMA_XFER_SIZE, size); lcdif_dma[i].dma.next = &lcdif_dma[(i + 1) % NR_CMDS].dma; lcdif_dma[i].dma.cmd = BF_OR3(APB_CHx_CMD, CHAIN(1), COMMAND(BV_APB_CHx_CMD_COMMAND__READ), XFER_COUNT(xfer)); lcdif_dma[i].dma.buffer = frame_p; size -= xfer; frame_p += xfer; } // first transfer: enable run, dotclk and so on lcdif_dma[0].dma.cmd |= BF_OR1(APB_CHx_CMD, CMDWORDS(1)); lcdif_dma[0].ctrl = BF_OR4(LCDIF_CTRL, BYPASS_COUNT(1), DOTCLK_MODE(1), RUN(1), WORD_LENGTH(1)); // enable lcd_enable(true); }
static void lcd_underflow(void) { /* on underflow, current frame is dead so stop lcdif and prepare for next frame * don't bother with the errata, fifo is empty since we are underflowing ! */ BF_CLR(LCDIF_CTRL, DOTCLK_MODE); imx233_dma_reset_channel(APB_LCDIF); imx233_dma_start_command(APB_LCDIF, &lcdif_dma[0].dma); }
void INT_I2C_ERROR(void) { /* reset dma channel on error */ if(imx233_dma_is_channel_error_irq(APB_I2C)) imx233_dma_reset_channel(APB_I2C); /* clear irq flags */ imx233_dma_clear_channel_interrupt(APB_I2C); semaphore_release(&i2c_sema); }
enum imx233_i2c_error_t imx233_i2c_end(unsigned timeout) { if(i2c_nr_stages == 0) return I2C_ERROR; i2c_stage[i2c_nr_stages - 1].dma.cmd |= BM_APB_CHx_CMD_SEMAPHORE | BM_APB_CHx_CMD_IRQONCMPLT; BF_CLR(I2C_CTRL1, ALL_IRQ); imx233_dma_reset_channel(APB_I2C); imx233_icoll_enable_interrupt(INT_SRC_I2C_DMA, true); imx233_icoll_enable_interrupt(INT_SRC_I2C_ERROR, true); imx233_dma_enable_channel_interrupt(APB_I2C, true); imx233_dma_start_command(APB_I2C, &i2c_stage[0].dma); enum imx233_i2c_error_t ret; if(semaphore_wait(&i2c_sema, timeout) == OBJ_WAIT_TIMEDOUT) { imx233_dma_reset_channel(APB_I2C); imx233_i2c_reset(); ret = I2C_TIMEOUT; } else if(BF_RD(I2C_CTRL1, MASTER_LOSS_IRQ)) ret = I2C_MASTER_LOSS; else if(BF_RD(I2C_CTRL1, NO_SLAVE_ACK_IRQ)) { /* the core doesn't like this error, this is a workaround to prevent lock up */ #if IMX233_SUBTARGET >= 3780 BF_SET(I2C_CTRL1, CLR_GOT_A_NAK); #endif imx233_dma_reset_channel(APB_I2C); imx233_i2c_reset(); ret = I2C_NO_SLAVE_ACK; } else if(BF_RD(I2C_CTRL1, EARLY_TERM_IRQ)) ret = I2C_SLAVE_NAK; else ret = imx233_i2c_finalize(); /* sleep */ BF_SET(I2C_CTRL0, CLKGATE); mutex_unlock(&i2c_mutex); return ret; }
void lcd_enable(bool enable) { if(lcd_active() == enable) return; lcd_set_active(enable); if(lcd_active()) { // enable spi spi_enable(true); // reset imx233_lcdif_reset_lcd(true); imx233_lcdif_reset_lcd(false); mdelay(1); imx233_lcdif_reset_lcd(true); mdelay(1); // "power" on lcd_power(true); // setup registers lcd_power_seq(); lcd_init_seq(); lcd_display_on_seq(); imx233_dma_reset_channel(APB_LCDIF); imx233_dma_start_command(APB_LCDIF, &lcdif_dma[0].dma); } else { // power down lcd_display_off_seq(); lcd_power(false); // stop lcdif BF_CLR(LCDIF_CTRL, DOTCLK_MODE); /* stmp37xx errata: clearing DOTCLK_MODE won't clear RUN: wait until * fifo is empty and then clear manually */ while(!BF_RD(LCDIF_STAT, TXFIFO_EMPTY)); BF_CLR(LCDIF_CTRL, RUN); // disable spi spi_enable(false); } }
void lcd_enable(bool enable) { if(lcd_on == enable) return; lcd_on = enable; if(lcd_on) { // enable spi spi_enable(true); // reset imx233_lcdif_reset_lcd(true); imx233_lcdif_reset_lcd(false); mdelay(1); imx233_lcdif_reset_lcd(true); mdelay(1); // "power" on lcd_power(true); // setup registers imx233_lcdif_enable_sync_signals(true); // we need frame signals during init lcd_power_seq(); lcd_init_seq(); lcd_display_on_seq(); imx233_dma_reset_channel(APB_LCDIF); imx233_dma_start_command(APB_LCDIF, &lcdif_dma[0].dma); BF_SET(LCDIF_CTRL, DOTCLK_MODE); BF_SET(LCDIF_CTRL, RUN); } else { // power down lcd_display_off_seq(); lcd_power(false); // stop lcdif BF_CLR(LCDIF_CTRL, DOTCLK_MODE); // disable spi spi_enable(false); } }