void bs_hw_done()//bool dealloc { if ( !(broadsheet_ignore_hw_ready() || broadsheet_force_hw_not_ready()) ) { // Wait until any pending operations are done before shutting down. // einkfb_debug("Waiting for HRDY before shutting down...\n"); wait_for_ready(); } #ifdef MXC31 #ifdef CONFIG_MACH_MX31ADS // Reset the level translator for the two GPIO inputs (HIRQ and HRDY) pin_addr = PBC_BCTRL2_LDCIO_EN; __raw_writew(pin_addr, PBC_BASE_ADDRESS + PBC_BCTRL2_CLEAR); mdelay(100); // Pause 100 ms to allow level translator to settle #elif CONFIG_MACH_MARIO_MX mxc_free_gpio(BROADSHEET_RST_LINE); #endif #ifdef USE_BS_IRQ disable_irq(BROADSHEET_HIRQ_IRQ); free_irq(BROADSHEET_HIRQ_IRQ, NULL); #endif mxc_free_gpio(BROADSHEET_HIRQ_LINE); mxc_free_gpio(BROADSHEET_HRDY_LINE); #endif einkfb_debug("Released Broadsheet GPIO pins and IRQs\n"); }
static void fslepdc_send_update_retry(struct work_struct *work) { if (fslepdc_removed) return; einkfb_debug("Retrying update, count = %d\n", fslepdc_send_update_retry_counter); fslepdc_send_update(&fslepdc_send_update_retry_data, FSLEPDC_UPDATE_RETRY); }
static irqreturn_t bs_irq_handler (int irq, void *data, struct pt_regs *r) { u16 irq_status; // Check Broadsheet general IRQs irq_status = bs_cmd_rd_reg(BS_INTR_RAW_STATUS_REG); einkfb_debug("BS_INTR_RAW_STATUS_REG = 0x%04X\n", irq_status); irq_status = bs_cmd_rd_reg(BS_DE_INTR_RAW_STATUS_REG); einkfb_debug("BS_DE_INTR_RAW_STATUS_REG = 0x%04X\n", irq_status); // Clear all interrupt flags bs_cmd_wr_reg(BS_INTR_RAW_STATUS_REG, BS_ALL_IRQS); bs_cmd_wr_reg(BS_DE_INTR_RAW_STATUS_REG, BS_DE_ALL_IRQS); return IRQ_HANDLED; }
// Scheduled loop for doing IO on framebuffer-sized buffers. // static int bs_io_buf(u32 data_size, u16 *data, bool which) { // display_port_t disp = BROADSHEET_DISPLAY_NUMBER; int result = EINKFB_FAILURE; dd_printk("[D] len=%i\n", data_size); einkfb_debug_full("size = %d\n", data_size); if ( BS_READY() ) { int i = 0, j, length = (EINKFB_MEMCPY_MIN >> 1), num_loops = data_size/length, remainder = data_size % length; bool done = false; if ( 0 != num_loops ) einkfb_debug("num_loops @ %d bytes = %d, remainder = %d\n", (length << 1), num_loops, (remainder << 1)); result = EINKFB_SUCCESS; // Read/write EINKFB_MEMCPY_MIN bytes (hence, divide by 2) at a time. While // there are still bytes to read/write, yield the CPU. // do { if ( 0 >= num_loops ) length = remainder; for ( j = 0; j < length; j++) { if ( BS_WR == which ) // ipu_adc_write_cmd(disp, DAT, (uint32_t)data[i + j], 0, 0); ipu_adc_write_cmd(DAT, (uint32_t)data[i + j]); else // data[i + j] = (u16)(ipu_adc_read_data(disp) & 0x0000FFFF); data[i + j] = (u16)(ipu_adc_read_data() & 0x0000FFFF); } i += length; if ( i < data_size ) { EINKFB_SCHEDULE(); num_loops--; } else done = true; } while ( !done ); } return ( result ); }
static void fslepdc_set_orientation(void) { // The displays for Whitney and Tequila are mounted upside down from Finkle. It // doesn't really matter on Yoshi, so we'll set it to Finkle's orientation. // Any devices that we don't know about yet will just be considered to be in // the default, upright orientation. // if ( mx50_board_is(BOARD_ID_YOSHI) || mx50_board_is(BOARD_ID_FINKLE) ) { fslepdc_orientation = fslepdc_orientation_ud; fslepdc_rotate = fslepdc_rotate_ud; einkfb_debug("orientation is upside down\n"); } else { fslepdc_orientation = fslepdc_orientation_ur; fslepdc_rotate = fslepdc_rotate_ur; einkfb_debug("orientation is upright\n"); } }
int einkfb_schedule_timeout(unsigned long hardware_timeout, einkfb_hardware_ready_t hardware_ready, void *data, bool interruptible) { int result = EINKFB_SUCCESS; if ( hardware_timeout && hardware_ready ) { if ( FORCE_INTERRUPTIBLE() || interruptible ) result = einkfb_schedule_timeout_guts(hardware_timeout, hardware_ready, data, INTERRUPTIBLE); else result = einkfb_schedule_timeout_uninterruptible(hardware_timeout, hardware_ready, data); } else { // Yield the CPU with schedule. // einkfb_debug("Yielding CPU with schedule.\n"); schedule(); } return ( result ); }
static char *fslepdc_waveform_version_io(char *path) { char *result = NULL; // If we're requesting that the in-use waveform version be returned... // if ( EINKFB_READ_WFV(path) ) { // ...then do that now. // einkwf_set_buffer(fslepdc_waveform_proxy); result = einkwf_get_waveform_version_string(eink_waveform_version_string); } else { // ...otherwise, read in the waveform from the passed-in path. // einkfb_debug("waveform path = %s\n", path); } return ( result ); }
static int einkfb_schedule_timeout_guts(unsigned long hardware_timeout, einkfb_hardware_ready_t hardware_ready, void *data, bool interruptible) { unsigned long start_time = jiffies, stop_time = start_time + hardware_timeout, timeout = CONTROLLER_COMMON_TIMEOUT_MIN; int result = EINKFB_SUCCESS; // Ask the hardware whether it's ready or not. And, if it's not ready, start yielding // the CPU for CONTROLLER_COMMON_TIMEOUT_MIN jiffies, increasing the yield time up to // CONTROLLER_COMMON_TIMEOUT_MAX jiffies. Time out after the requested number of // of jiffies has occurred. // while ( !(*hardware_ready)(data) && time_before_eq(jiffies, stop_time) ) { timeout = min(timeout++, CONTROLLER_COMMON_TIMEOUT_MAX); if ( interruptible ) schedule_timeout_interruptible(timeout); else schedule_timeout(timeout); } if ( time_after(jiffies, stop_time) ) { einkfb_print_crit("Timed out waiting for the hardware to become ready!\n"); result = EINKFB_FAILURE; } else { // For debugging purposes, dump the time it took for the hardware to // become ready if it was more than CONTROLLER_COMMON_TIMEOUT_MAX. // stop_time = jiffies - start_time; if ( CONTROLLER_COMMON_TIMEOUT_MAX < stop_time ) einkfb_debug("Timeout time = %ld\n", stop_time); } return ( result ); }
void einkfb_set_contrast(contrast_t contrast) { switch ( contrast ) { case contrast_lightest: case contrast_lighter: case contrast_light: case contrast_medium: case contrast_dark: case contrast_darker: case contrast_darkest: case contrast_invert: case contrast_off: einkfb_contrast = contrast; break; default: einkfb_contrast = contrast_off; break; } einkfb_debug("contrast = %d\n", einkfb_contrast); }
bool bs_quickly_hw_init(void) { bool result = true; if (bsaddr == NULL) { bsaddr = ioremap(0x10000000, 4); } if ((unsigned int)bsaddr < 0xa0000000) { iounmap(bsaddr); bsaddr = ioremap(0x10000000, 4); } //reset broadsheet // GPC7 EINK_3.3V_EN config output gpcon = __raw_readl(S3C64XX_GPCCON); gpcon = gpcon & ~(0xF << 28); __raw_writel(gpcon | (0x1 << 28), S3C64XX_GPCCON); //GPC7 EINK_3.3V_EN set low gpdata = __raw_readl(S3C64XX_GPCDAT); gpdata =(gpdata & ~(1<<7)); __raw_writel(gpdata,S3C64XX_GPCDAT); //GPC6 EINK_1.8V_EN config output gpcon = __raw_readl(S3C64XX_GPCCON); gpcon = gpcon & ~(0xF << 24); __raw_writel(gpcon | (0x1 << 24), S3C64XX_GPCCON); //GPC6 EINK_1.8V_EN set low gpdata = __raw_readl(S3C64XX_GPCDAT); gpdata =(gpdata & ~(1<<6)); __raw_writel(gpdata,S3C64XX_GPCDAT); //GPP2 OSC_EN config output gpcon = __raw_readl(S3C64XX_GPPCON); gpcon = (gpcon & ~(3<<4)); __raw_writel(gpcon|(0x1<<4), S3C64XX_GPPCON); //GPP2 OSC_EN set high gpdata = __raw_readl(S3C64XX_GPPDAT); gpdata =(gpdata & ~(1<<2)); __raw_writel(gpdata|(0x1<<2),S3C64XX_GPPDAT); mdelay(10); //GPP9 HnRST config output HIGH_RESET_PIN; gpcon = __raw_readl(S3C64XX_GPPCON); gpcon = (gpcon & ~(3<<18)); __raw_writel(gpcon|(0x1<<18), S3C64XX_GPPCON); HIGH_RESET_PIN; udelay(100); LOW_RESET_PIN; udelay(100); HIGH_RESET_PIN; //setup HD/C signalconfig gpcon = __raw_readl(S3C64XX_GPOCON); gpcon =(gpcon & ~(3<<4)); __raw_writel(gpcon|(0x1<<4),S3C64XX_GPOCON); gpdata = __raw_readl(S3C64XX_GPODAT); gpdata =(gpdata & ~(1<<2)); __raw_writel(gpdata|(0x1<<2),S3C64XX_GPODAT); //GPO3 HIRQ config input gpcon = __raw_readl(S3C64XX_GPOCON); gpcon = (gpcon & ~(3<<6)); __raw_writel(gpcon, S3C64XX_GPOCON); //now HRDY setup to input gpcon = __raw_readl(S3C64XX_GPOCON); gpcon = (gpcon & ~(3<<8)); __raw_writel(gpcon, S3C64XX_GPOCON); sromdata = __raw_readl(S3C64XX_VA_SROMC); sromdata &=~(0xF<<0); sromdata |= (1<<3) | (1<<2) | (1<<0); __raw_writel(sromdata, S3C64XX_VA_SROMC); //SROM_BC0 config //__raw_writel((0x1<<28)|(0xf<<24)|(0x1c<<16)|(0x1<<12)|(0x6<<8)|(0x2<<4)|(0x0<<0), S3C64XX_VA_SROMC+4); __raw_writel((0x0<<28)|(0x0<<24)|(0xA<<16)|(0x1<<12)|(0x0<<8)|(0x2<<4)|(0x0<<0), S3C64XX_VA_SROMC+4); //printk(KERN_ALERT "Product id is %x\n",__raw_readw(bsaddr)); //printk(KERN_ALERT "The new bs driver\n"); //ipu_adc_write_cmd(CMD,0x11); //ipu_adc_write_cmd(DAT,0x030a); //ipu_adc_write_cmd(DAT,0x0123); /* ipu_adc_write_cmd(CMD,0x10); __raw_writew(0x02,bsaddr); udelay(1); printk(KERN_ALERT "Product id re-get is %x\n",__raw_readw(bsaddr)); //printk(KERN_ALERT "The new bs driver\n"); ipu_adc_write_cmd(CMD,0x10); ipu_adc_write_cmd(DAT,0x02); printk(KERN_ALERT "register 0x0002 content is 0x%4x\n",ipu_adc_read_data()); */ #if defined(CONFIG_HW_EP3_DVT) || defined(CONFIG_HW_EP4_DVT) || defined(CONFIG_HW_EP1_DVT) || defined(CONFIG_HW_EP2_DVT) u16 rd_reg; unsigned short value = 0; rd_reg = bs_cmd_rd_reg(0x00a) & ~(1 << 12); bs_cmd_wr_reg(0x00a, (value | (1 << 12))); //REG[000Ah] bit 12 = 1b //Henry Li 0927 fro saving time in resume mdelay(4); bs_cmd_init_sys_run(); udelay(EPD_CMD_DELAY); rd_reg=0; while(!value) { value = GET_HRDY_STATUS; udelay(50); rd_reg++; if (rd_reg > 60000) break; } //rd_reg = bs_cmd_rd_reg(0x0204) | (1 << 7); // spi flash control reg: Display Engine access mode is selected. rd_reg = 0x99; bs_cmd_wr_reg(0x0204, rd_reg); //Henry Li 0927 fro saving time in resume /* udelay(EPD_CMD_DELAY); printk("reg[0x0204] is 0x%x\n", rd_reg); */ #endif //Henry Li 0927 fro saving time in resume /* ipu_adc_write_cmd(CMD,0x10); ipu_adc_write_cmd(DAT,0x02); printk(KERN_ALERT "register 0x0002 content is 0x%4x\n",ipu_adc_read_data()); */ einkfb_debug("GPIOs and IRQ set; Broadsheet has been reset\n"); #if defined(CONFIG_HW_EP3_DVT) || defined(CONFIG_HW_EP4_DVT) /* //Henry Li 0927 fro saving time in resume mdelay(1); */ bs_cmd_wr_reg(0x300, BS97_INIT_VSIZE); //Frame Data Length Register //Henry: as instruction code init it as 825 //Henry Li 0927 fro saving time in resume mdelay(1); #endif return ( result ); }
bool bs_hw_init(void) { bool result = true; bsaddr = ioremap(0x10000000, 4); //printk(KERN_ALERT "hello broadsheet!\n"); //reset broadsheet // GPC7 EINK_3.3V_EN config output gpcon = __raw_readl(S3C64XX_GPCCON); gpcon = gpcon & ~(0xF << 28); __raw_writel(gpcon | (0x1 << 28), S3C64XX_GPCCON); //GPC7 EINK_3.3V_EN set low gpdata = __raw_readl(S3C64XX_GPCDAT); gpdata =(gpdata & ~(1<<7)); __raw_writel(gpdata,S3C64XX_GPCDAT); //GPC6 EINK_1.8V_EN config output gpcon = __raw_readl(S3C64XX_GPCCON); gpcon = gpcon & ~(0xF << 24); __raw_writel(gpcon | (0x1 << 24), S3C64XX_GPCCON); //GPC6 EINK_1.8V_EN set low gpdata = __raw_readl(S3C64XX_GPCDAT); gpdata =(gpdata & ~(1<<6)); __raw_writel(gpdata,S3C64XX_GPCDAT); //GPP2 OSC_EN config output gpcon = __raw_readl(S3C64XX_GPPCON); gpcon = (gpcon & ~(3<<4)); __raw_writel(gpcon|(0x1<<4), S3C64XX_GPPCON); //GPP2 OSC_EN set high gpdata = __raw_readl(S3C64XX_GPPDAT); gpdata =(gpdata & ~(1<<2)); __raw_writel(gpdata|(0x1<<2),S3C64XX_GPPDAT); mdelay(10); //GPP9 HnRST config output gpcon = __raw_readl(S3C64XX_GPPCON); gpcon = (gpcon & ~(3<<18)); __raw_writel(gpcon|(0x1<<18), S3C64XX_GPPCON); HIGH_RESET_PIN; mdelay(10); LOW_RESET_PIN; mdelay(100); HIGH_RESET_PIN; //setup HD/C signalconfig gpcon = __raw_readl(S3C64XX_GPOCON); gpcon =(gpcon & ~(3<<4)); __raw_writel(gpcon|(0x1<<4),S3C64XX_GPOCON); gpdata = __raw_readl(S3C64XX_GPODAT); gpdata =(gpdata & ~(1<<2)); __raw_writel(gpdata|(0x1<<2),S3C64XX_GPODAT); //GPO3 HIRQ config input gpcon = __raw_readl(S3C64XX_GPOCON); gpcon = (gpcon & ~(3<<6)); __raw_writel(gpcon, S3C64XX_GPOCON); //now HRDY setup to input gpcon = __raw_readl(S3C64XX_GPOCON); gpcon = (gpcon & ~(3<<8)); __raw_writel(gpcon, S3C64XX_GPOCON); sromdata = __raw_readl(S3C64XX_VA_SROMC); sromdata &=~(0xF<<0); sromdata |= (1<<3) | (1<<2) | (1<<0); __raw_writel(sromdata, S3C64XX_VA_SROMC); //SROM_BC0 config //__raw_writel((0x1<<28)|(0xf<<24)|(0x1c<<16)|(0x1<<12)|(0x6<<8)|(0x2<<4)|(0x0<<0), S3C64XX_VA_SROMC+4); __raw_writel((0x0<<28)|(0x0<<24)|(0xA<<16)|(0x1<<12)|(0x0<<8)|(0x2<<4)|(0x0<<0), S3C64XX_VA_SROMC+4); //printk(KERN_ALERT "Product id is %x\n",__raw_readw(bsaddr)); //printk(KERN_ALERT "The new bs driver\n"); #ifdef MXC31 for(i=0;i<100;i++) { mdelay(500); __raw_writew(0xffff,bsaddr); //printk(KERN_ALERT "write the %dth times data\n",i); } #endif #ifdef USE_BS_IRQ int rqstatus; #endif #ifdef MXC31 ipu_adc_sig_cfg_t sig = { 0, 0, 0, 0, 0, 0, 0, 0, IPU_ADC_BURST_WCS, IPU_ADC_IFC_MODE_SYS80_TYPE2, 16, 0, 0, IPU_ADC_SER_NO_RW }; // Init DI interface if ( IS_NELL() || IS_MARIO() || IS_ADS() ) { broadsheet_screen_height = BROADSHEET_SCREEN_HEIGHT_NELL; broadsheet_screen_width = BROADSHEET_SCREEN_WIDTH_NELL; broadsheet_screen_size = BROADSHEET_SCREEN_SIZE_NELL; } ipu_adc_init_panel(BROADSHEET_DISPLAY_NUMBER, broadsheet_screen_width, broadsheet_screen_height, BROADSHEET_PIXEL_FORMAT, broadsheet_screen_size, sig, XY, 0, VsyncInternal); // Set IPU timing for read cycles ipu_adc_init_ifc_timing(BROADSHEET_DISPLAY_NUMBER, true, BROADSHEET_READ_CYCLE_TIME, BROADSHEET_READ_UP_TIME, BROADSHEET_READ_DOWN_TIME, BROADSHEET_READ_LATCH_TIME, BROADSHEET_PIXEL_CLK); // Set IPU timing for write cycles ipu_adc_init_ifc_timing(BROADSHEET_DISPLAY_NUMBER, false, BROADSHEET_WRITE_CYCLE_TIME, BROADSHEET_WRITE_UP_TIME, BROADSHEET_WRITE_DOWN_TIME, 0, 0); ipu_adc_set_update_mode(ADC_SYS1, IPU_ADC_REFRESH_NONE, 0, 0, 0); gpio_lcd_active(); slcd_gpio_config(); #ifdef CONFIG_MACH_MX31ADS // Reset the level translator for the two GPIO inputs (HIRQ and HRDY) pin_addr = PBC_BCTRL2_LDCIO_EN; __raw_writew(pin_addr, PBC_BASE_ADDRESS + PBC_BCTRL2_CLEAR); #endif #ifdef USE_BS_IRQ // Set up IRQ for for Broadsheet HIRQ line disable_irq(BROADSHEET_HIRQ_IRQ); set_irq_type(BROADSHEET_HIRQ_IRQ, IRQF_TRIGGER_RISING); rqstatus = request_irq(BROADSHEET_HIRQ_IRQ, (irq_handler_t) bs_irq_handler, 0, "eink_fb_hal_broads", NULL); if (rqstatus != 0) { einkfb_print_crit("Failed IRQ request for Broadsheet HIRQ line; request status = %d\n", rqstatus); result = false; } #endif // Set up GPIO pins if (mxc_request_gpio(BROADSHEET_HIRQ_LINE)) { einkfb_print_crit("Could not obtain GPIO pin for HIRQ\n"); result = false; } else { // Set HIRQ pin as input mxc_set_gpio_direction(BROADSHEET_HIRQ_LINE, 1); } if (mxc_request_gpio(BROADSHEET_HRDY_LINE)) { einkfb_print_crit("Could not obtain GPIO pin for HRDY\n"); result = false; } else { // Set HRDY pin as input mxc_set_gpio_direction(BROADSHEET_HRDY_LINE, 1); } #ifdef CONFIG_MACH_MARIO_MX if (mxc_request_gpio(BROADSHEET_RST_LINE)) { einkfb_print_crit("Could not obtain GPIO pin for RST\n"); result = false; } else { // Set RST pin as output and initialize to zero (it's active LOW) mxc_set_gpio_direction(BROADSHEET_RST_LINE, 0); mxc_set_gpio_dataout(BROADSHEET_RST_LINE, 0); } #endif #ifdef CONFIG_MACH_MX31ADS // Enable the level translator for the two GPIO inputs (HIRQ and HRDY) mdelay(100); // Pause 100 ms to allow level translator to settle pin_addr = PBC_BCTRL2_LDCIO_EN; __raw_writew(pin_addr, PBC_BASE_ADDRESS + PBC_BCTRL2_SET); #endif // Reset Broadsheet einkfb_debug("Sending RST signal to Broadsheet...\n"); LOW_RESET_PIN; //WR_GPIO_LINE(BROADSHEET_RST_LINE, BROADSHEET_RESET_VAL); // Assert RST mdelay(100); // Pause 100 ms during reset HIGH_RESET_PIN; //WR_GPIO_LINE(BROADSHEET_RST_LINE, BROADSHEET_NON_RESET_VAL); // Clear RST mdelay(400); // Pause 400 ms to allow Broasheet time to come up einkfb_debug("Broadsheet reset done.\n"); //#ifdef TEST_BROADSHEET // test_broadsheet(disp); //#endif #endif #ifdef USE_BS_IRQ // Set up Broadsheet for interrupt generation (enable all conditions) bs_cmd_wr_reg(BS_INTR_CTL_REG, BS_ALL_IRQS); bs_cmd_wr_reg(BS_INTR_RAW_STATUS_REG, BS_ALL_IRQS); // Enable all Broadsheet display engine interrupts bs_cmd_wr_reg(BS_DE_INTR_ENABLE_REG, BS_DE_ALL_IRQS); bs_cmd_wr_reg(BS_DE_INTR_RAW_STATUS_REG, BS_DE_ALL_IRQS); #endif //ipu_adc_write_cmd(CMD,0x11); //ipu_adc_write_cmd(DAT,0x030a); //ipu_adc_write_cmd(DAT,0x0123); /* ipu_adc_write_cmd(CMD,0x10); __raw_writew(0x02,bsaddr); udelay(1); printk(KERN_ALERT "Product id re-get is %x\n",__raw_readw(bsaddr)); //printk(KERN_ALERT "The new bs driver\n"); */ #if defined(CONFIG_HW_EP3_DVT) || defined(CONFIG_HW_EP4_DVT) || defined(CONFIG_HW_EP1_DVT) || defined(CONFIG_HW_EP2_DVT) u16 rd_reg; unsigned short value = 0; rd_reg = bs_cmd_rd_reg(0x00a) & ~(1 << 12); bs_cmd_wr_reg(0x00a, (value | (1 << 12))); //REG[000Ah] bit 12 = 1b //Henry Li 0927 fro saving time in resume mdelay(4); bs_cmd_init_sys_run(); udelay(EPD_CMD_DELAY); rd_reg=0; while(!value) { value = GET_HRDY_STATUS; udelay(50); rd_reg++; if (rd_reg > 60000) break; } //rd_reg = bs_cmd_rd_reg(0x0204) | (1 << 7); // spi flash control reg: Display Engine access mode is selected. rd_reg = 0x99; bs_cmd_wr_reg(0x0204, rd_reg); /* //Henry Li 0927 fro saving time in resume udelay(EPD_CMD_DELAY); printk("reg[0x0204] is 0x%x\n", rd_reg); */ #endif /* //Henry Li 0927 fro saving time in resume ipu_adc_write_cmd(CMD,0x10); ipu_adc_write_cmd(DAT,0x02); printk(KERN_ALERT "register 0x0002 content is 0x%4x\n",ipu_adc_read_data()); */ einkfb_debug("GPIOs and IRQ set; Broadsheet has been reset\n"); #if defined(CONFIG_HW_EP3_DVT) || defined(CONFIG_HW_EP4_DVT) /* //Henry Li 0927 fro saving time in resume mdelay(1); */ bs_cmd_wr_reg(0x300, BS97_INIT_VSIZE); //Frame Data Length Register //Henry: as instruction code init it as 825 /* //Henry Li 0927 fro saving time in resume mdelay(1); */ #endif return ( result ); }
static bool fslepdc_send_update(struct mxcfb_update_data *update_data, bool retry) { bool result = false; if ( update_data ) { unsigned long start_time, stop_time; int send_update_err; // If this isn't a retry... // if ( !retry ) { // ...cancel any pending retries. // cancel_delayed_work(&fslepdc_send_update_work); // But accumulate any pending retry with the new data. // if ( fslepdc_send_update_retry_counter ) { struct mxcfb_rect old_retry = fslepdc_send_update_retry_data.update_region, new_retry, update = update_data->update_region; u32 old_retry_right, old_retry_bot, new_retry_right, new_retry_bot, update_right, update_bot; // First, accumulate the update region. // old_retry_right = (old_retry.left + old_retry.width) - 1; old_retry_bot = (old_retry.top + old_retry.height) - 1; update_right = (update.left + update.width) - 1; update_bot = (update.top + update.height) - 1; new_retry.left = min(old_retry.left, update.left); new_retry.top = min(old_retry.top, update.top); new_retry_right = max(old_retry_right, update_right); new_retry_bot = max(old_retry_bot, update_bot); new_retry.width = (new_retry_right - new_retry.left) + 1; new_retry.height = (new_retry_bot - new_retry.top) + 1; fslepdc_send_update_retry_data.update_region = new_retry; // Since it's a retry, go for the highest fidelity possible. // fslepdc_send_update_retry_data.waveform_mode = fslepdc_get_waveform_mode(WF_UPD_MODE_GC); fslepdc_send_update_retry_data.update_mode = UPDATE_MODE_FULL; // Use the latest marker and temperature. // fslepdc_send_update_retry_data.update_marker = update_data->update_marker; fslepdc_send_update_retry_data.temp = update_data->temp; // Copy the retry data back for this attempt. // *update_data = fslepdc_send_update_retry_data; } } // We can get errors sending updates to EPDC if it's not ready to do // an update yet. So, back off and retry a few times here first // before scheduling a retry. // start_time = jiffies; stop_time = start_time + FSLEPDC_SU_TIMEOUT; do { send_update_err = mxc_epdc_fb_send_update(update_data, NULL); if ( 0 != send_update_err ) { einkfb_print_error("EPDC_send_update_error=%d:\n", send_update_err); schedule_timeout_uninterruptible(FSLEPDC_SU_WAIT); } } while ( (0 != send_update_err) && time_before_eq(jiffies, stop_time) ); if ( time_after(jiffies, stop_time) ) { einkfb_print_crit("EDPC_send_update_timed_out=true:\n"); } else { char temp_string[16]; if ( TEMP_USE_AMBIENT == update_data->temp ) strcpy(temp_string, "ambient"); else sprintf(temp_string, "%d", update_data->temp); einkfb_debug("update_data:\n"); einkfb_debug(" rect x: %d\n", update_data->update_region.left); einkfb_debug(" rect y: %d\n", update_data->update_region.top); einkfb_debug(" rect w: %d\n", update_data->update_region.width); einkfb_debug(" rect h: %d\n", update_data->update_region.height); einkfb_debug(" wfmode: %d\n", update_data->waveform_mode); einkfb_debug(" update: %s\n", update_data->update_mode ? "flashing" : "non-flashing"); einkfb_debug(" marker: %d\n", update_data->update_marker); einkfb_debug(" temp: %s\n", temp_string); fslepdc_send_update_retry_counter = 0; result = true; } // If our attempt to send an update failed, try it again later. // if ( !result ) { if ( FSLEPDC_SU_RETRIES > ++fslepdc_send_update_retry_counter ) { // If this isn't a retry, use the current update data. // if ( !retry ) fslepdc_send_update_retry_data = *update_data; schedule_delayed_work(&fslepdc_send_update_work, FSLEPDC_SU_DELAY); } else { einkfb_print_crit("Updates are failing...\n"); } } } return ( result ); }
bool bs_hw_init(void) { bool result = true; #ifdef USE_BS_IRQ int rqstatus; #endif ipu_adc_sig_cfg_t sig = { 0, 0, 0, 0, 0, 0, 0, 0, IPU_ADC_BURST_WCS, IPU_ADC_IFC_MODE_SYS80_TYPE2, 16, 0, 0, IPU_ADC_SER_NO_RW }; // Init DI interface if ( IS_NELL() || IS_MARIO() || IS_ADS() ) { broadsheet_screen_height = BROADSHEET_SCREEN_HEIGHT_NELL; broadsheet_screen_width = BROADSHEET_SCREEN_WIDTH_NELL; broadsheet_screen_size = BROADSHEET_SCREEN_SIZE_NELL; } ipu_adc_init_panel(BROADSHEET_DISPLAY_NUMBER, broadsheet_screen_width, broadsheet_screen_height, BROADSHEET_PIXEL_FORMAT, broadsheet_screen_size, sig, XY, 0, VsyncInternal); // Set IPU timing for read cycles ipu_adc_init_ifc_timing(BROADSHEET_DISPLAY_NUMBER, true, BROADSHEET_READ_CYCLE_TIME, BROADSHEET_READ_UP_TIME, BROADSHEET_READ_DOWN_TIME, BROADSHEET_READ_LATCH_TIME, BROADSHEET_PIXEL_CLK); // Set IPU timing for write cycles ipu_adc_init_ifc_timing(BROADSHEET_DISPLAY_NUMBER, false, BROADSHEET_WRITE_CYCLE_TIME, BROADSHEET_WRITE_UP_TIME, BROADSHEET_WRITE_DOWN_TIME, 0, 0); ipu_adc_set_update_mode(ADC_SYS1, IPU_ADC_REFRESH_NONE, 0, 0, 0); gpio_lcd_active(); slcd_gpio_config(); #ifdef CONFIG_MACH_MX31ADS // Reset the level translator for the two GPIO inputs (HIRQ and HRDY) pin_addr = PBC_BCTRL2_LDCIO_EN; __raw_writew(pin_addr, PBC_BASE_ADDRESS + PBC_BCTRL2_CLEAR); #endif #ifdef USE_BS_IRQ // Set up IRQ for for Broadsheet HIRQ line disable_irq(BROADSHEET_HIRQ_IRQ); set_irq_type(BROADSHEET_HIRQ_IRQ, IRQF_TRIGGER_RISING); rqstatus = request_irq(BROADSHEET_HIRQ_IRQ, (irq_handler_t) bs_irq_handler, 0, "eink_fb_hal_broads", NULL); if (rqstatus != 0) { einkfb_print_crit("Failed IRQ request for Broadsheet HIRQ line; request status = %d\n", rqstatus); result = false; } #endif // Set up GPIO pins if (mxc_request_gpio(BROADSHEET_HIRQ_LINE)) { einkfb_print_crit("Could not obtain GPIO pin for HIRQ\n"); result = false; } else { // Set HIRQ pin as input mxc_set_gpio_direction(BROADSHEET_HIRQ_LINE, 1); } if (mxc_request_gpio(BROADSHEET_HRDY_LINE)) { einkfb_print_crit("Could not obtain GPIO pin for HRDY\n"); result = false; } else { // Set HRDY pin as input mxc_set_gpio_direction(BROADSHEET_HRDY_LINE, 1); } #ifdef CONFIG_MACH_MARIO_MX if (mxc_request_gpio(BROADSHEET_RST_LINE)) { einkfb_print_crit("Could not obtain GPIO pin for RST\n"); result = false; } else { // Set RST pin as output and initialize to zero (it's active LOW) mxc_set_gpio_direction(BROADSHEET_RST_LINE, 0); mxc_set_gpio_dataout(BROADSHEET_RST_LINE, 0); } #endif #ifdef CONFIG_MACH_MX31ADS // Enable the level translator for the two GPIO inputs (HIRQ and HRDY) mdelay(100); // Pause 100 ms to allow level translator to settle pin_addr = PBC_BCTRL2_LDCIO_EN; __raw_writew(pin_addr, PBC_BASE_ADDRESS + PBC_BCTRL2_SET); #endif // Reset Broadsheet einkfb_debug("Sending RST signal to Broadsheet...\n"); WR_GPIO_LINE(BROADSHEET_RST_LINE, BROADSHEET_RESET_VAL); // Assert RST mdelay(100); // Pause 100 ms during reset WR_GPIO_LINE(BROADSHEET_RST_LINE, BROADSHEET_NON_RESET_VAL); // Clear RST mdelay(400); // Pause 400 ms to allow Broasheet time to come up einkfb_debug("Broadsheet reset done.\n"); #ifdef TEST_BROADSHEET test_broadsheet(disp); #endif #ifdef USE_BS_IRQ // Set up Broadsheet for interrupt generation (enable all conditions) bs_cmd_wr_reg(BS_INTR_CTL_REG, BS_ALL_IRQS); bs_cmd_wr_reg(BS_INTR_RAW_STATUS_REG, BS_ALL_IRQS); // Enable all Broadsheet display engine interrupts bs_cmd_wr_reg(BS_DE_INTR_ENABLE_REG, BS_DE_ALL_IRQS); bs_cmd_wr_reg(BS_DE_INTR_RAW_STATUS_REG, BS_DE_ALL_IRQS); #endif einkfb_debug("GPIOs and IRQ set; Broadsheet has been reset\n"); return ( result ); }