int decon_get_hdmi_config(struct decon_device *decon, struct exynos_hdmi_data *hdmi_data) { struct v4l2_control ctrl; int ret = 0; ctrl.id = 0; ctrl.value = 0; decon_dbg("state : %d\n", hdmi_data->state); switch (hdmi_data->state) { case EXYNOS_HDMI_STATE_PRESET: ret = v4l2_subdev_call(decon->output_sd, video, g_dv_timings, &hdmi_data->timings); if (ret) decon_err("failed to get current timings\n"); else ret = find_subdev_hdmi(decon); decon_dbg("%dx%d@%s %lldHz %s(%#x)\n", hdmi_data->timings.bt.width, hdmi_data->timings.bt.height, hdmi_data->timings.bt.interlaced ? "I" : "P", hdmi_data->timings.bt.pixelclock, hdmi_data->timings.type ? "S3D" : "2D", hdmi_data->timings.type); break; case EXYNOS_HDMI_STATE_ENUM_PRESET: ret = v4l2_subdev_call(decon->output_sd, video, enum_dv_timings, &hdmi_data->etimings); if (ret) decon_err("failed to enumerate timings\n"); break; case EXYNOS_HDMI_STATE_CEC_ADDR: ctrl.id = V4L2_CID_TV_SOURCE_PHY_ADDR; ret = v4l2_subdev_call(decon->output_sd, core, g_ctrl, &ctrl); if (ret) decon_err("failed to get physical address for CEC\n"); hdmi_data->cec_addr = ctrl.value; decon_dbg("get physical address for CEC: %#x\n", hdmi_data->cec_addr); break; case EXYNOS_HDMI_STATE_AUDIO: ctrl.id = V4L2_CID_TV_MAX_AUDIO_CHANNELS; ret = v4l2_subdev_call(decon->output_sd, core, g_ctrl, &ctrl); if (ret) decon_err("failed to get hdmi audio information\n"); hdmi_data->audio_info = ctrl.value; break; default: decon_warn("unrecongnized state %u", hdmi_data->state); ret = -EINVAL; break; } return ret; }
irqreturn_t decon_t_irq_handler(int irq, void *dev_data) { struct decon_device *decon = dev_data; u32 irq_sts_reg; spin_lock(&decon->slock); if ((decon->state == DECON_STATE_OFF) || (decon->state == DECON_STATE_LPD)) { goto irq_end; } irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id); if (irq_sts_reg & INTERRUPT_FIFO_LEVEL_INT_EN) { DISP_SS_EVENT_LOG(DISP_EVT_UNDERRUN, &decon->sd, ktime_set(0, 0)); decon_err("DECON_T FIFO underrun\n"); } if (irq_sts_reg & INTERRUPT_FRAME_DONE_INT_EN) { decon_lpd_trig_reset(decon); DISP_SS_EVENT_LOG(DISP_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0)); decon_dbg("%s Frame Done is occured. timeline:%d, %d\n", __func__, decon->timeline->value, decon->timeline_max); } if (irq_sts_reg & INTERRUPT_RESOURCE_CONFLICT_INT_EN) DISP_SS_EVENT_LOG(DISP_EVT_RSC_CONFLICT, &decon->sd, ktime_set(0, 0)); irq_end: spin_unlock(&decon->slock); return IRQ_HANDLED; }
void decon_t_set_clocks(struct decon_device *decon) { struct device *dev = decon->dev; struct decon_clocks clks; struct decon_param p; decon_to_init_param(decon, &p); decon_reg_get_clock_ratio(&clks, p.lcd_info); /* ECLK */ decon_clk_set_rate(dev, decon->res.eclk, NULL, clks.decon[CLK_ID_ECLK] * MHZ); decon_clk_set_rate(dev, decon->res.eclk_leaf, NULL, clks.decon[CLK_ID_ECLK] * MHZ); #if defined(CONFIG_EXYNOS8890_BTS_OPTIMIZATION) /* TODO: hard-coded 42 will be changed * default MIC factor is 3, So default VCLK is 42 for calculating DISP */ decon->vclk_factor = 42 * DECON_PIX_PER_CLK; #endif decon_dbg("%s: pclk %ld eclk %ld Mhz\n", __func__, clk_get_rate(decon->res.pclk) / MHZ, clk_get_rate(decon->res.eclk_leaf) / MHZ); return; }
int decon_set_hdmi_config(struct decon_device *decon, struct exynos_hdmi_data *hdmi_data) { struct v4l2_control ctrl; int ret = 0; decon_dbg("state : %d\n", hdmi_data->state); switch (hdmi_data->state) { case EXYNOS_HDMI_STATE_PRESET: ret = v4l2_subdev_call(decon->output_sd, video, s_dv_timings, &hdmi_data->timings); if (ret) decon_err("failed to set timings newly\n"); else ret = find_subdev_hdmi(decon); decon_dbg("%dx%d@%s %lldHz %s(%#x)\n", hdmi_data->timings.bt.width, hdmi_data->timings.bt.height, hdmi_data->timings.bt.interlaced ? "I" : "P", hdmi_data->timings.bt.pixelclock, hdmi_data->timings.type ? "S3D" : "2D", hdmi_data->timings.type); break; case EXYNOS_HDMI_STATE_HDCP: ctrl.id = V4L2_CID_TV_HDCP_ENABLE; ctrl.value = hdmi_data->hdcp; ret = v4l2_subdev_call(decon->output_sd, core, s_ctrl, &ctrl); if (ret) decon_err("failed to enable HDCP\n"); decon_dbg("HDCP %s\n", ctrl.value ? "enabled" : "disabled"); break; case EXYNOS_HDMI_STATE_AUDIO: ctrl.id = V4L2_CID_TV_SET_NUM_CHANNELS; ctrl.value = hdmi_data->audio_info; ret = v4l2_subdev_call(decon->output_sd, core, s_ctrl, &ctrl); if (ret) decon_err("failed to set hdmi audio information\n"); break; default: decon_warn("unrecongnized state %u", hdmi_data->state); ret = -EINVAL; break; } return ret; }
irqreturn_t decon_ext_dsi_irq_handler(int irq, void *dev_data) { struct decon_device *decon = dev_data; ktime_t timestamp = ktime_get(); u32 irq_sts_reg; u32 wb_irq_sts_reg; spin_lock(&decon->slock); irq_sts_reg = decon_read(decon->id, VIDINTCON1); wb_irq_sts_reg = decon_read(decon->id, VIDINTCON3); if (irq_sts_reg & VIDINTCON1_INT_FRAME) { /* VSYNC interrupt, accept it */ decon_write_mask(decon->id, VIDINTCON1, ~0, VIDINTCON1_INT_FRAME); decon->vsync_info.timestamp = timestamp; wake_up_interruptible_all(&decon->vsync_info.wait); } if (irq_sts_reg & VIDINTCON1_INT_FIFO) { decon_err("DECON-ext FIFO underrun\n"); decon_write_mask(decon->id, VIDINTCON1, ~0, VIDINTCON1_INT_FIFO); } if (irq_sts_reg & VIDINTCON1_INT_I80) { decon_write_mask(decon->id, VIDINTCON1, ~0, VIDINTCON1_INT_I80); wake_up_interruptible_all(&decon->wait_frmdone); } #if 0 if (wb_irq_sts_reg & VIDINTCON3_WB_FRAME_DONE) { decon_dbg("write-back frame done\n"); DISP_SS_EVENT_LOG(DISP_EVT_WB_FRAME_DONE, &decon->sd, ktime_set(0, 0)); decon_write_mask(decon->id, VIDINTCON3, ~0, VIDINTCON3_WB_FRAME_DONE); atomic_set(&decon->wb_done, STATE_DONE); wake_up_interruptible_all(&decon->wait_frmdone); decon_reg_per_frame_off(decon->id); decon_reg_update_standalone(decon->id); decon_reg_wb_swtrigger(decon->id); decon_reg_wait_stop_status_timeout(decon->id, 20 * 1000); } #endif spin_unlock(&decon->slock); return IRQ_HANDLED; }
int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct decon_win *win = info->par; struct decon_device *decon = win->decon; int x, y; unsigned long long hz; var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = max(var->yres_virtual, var->yres); if (!decon_validate_x_alignment(decon, 0, var->xres, var->bits_per_pixel)) return -EINVAL; /* always ensure these are zero, for drop through cases below */ var->transp.offset = 0; var->transp.length = 0; switch (var->bits_per_pixel) { case 1: case 2: case 4: case 8: var->red.offset = 4; var->green.offset = 2; var->blue.offset = 0; var->red.length = 5; var->green.length = 3; var->blue.length = 2; var->transp.offset = 7; var->transp.length = 1; break; case 19: /* 666 with one bit alpha/transparency */ var->transp.offset = 18; var->transp.length = 1; case 18: var->bits_per_pixel = 32; /* 666 format */ var->red.offset = 12; var->green.offset = 6; var->blue.offset = 0; var->red.length = 6; var->green.length = 6; var->blue.length = 6; break; case 16: /* 16 bpp, 565 format */ var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; var->red.length = 5; var->green.length = 6; var->blue.length = 5; break; case 32: case 28: case 25: var->transp.length = var->bits_per_pixel - 24; var->transp.offset = 24; /* drop through */ case 24: /* our 24bpp is unpacked, so 32bpp */ var->bits_per_pixel = 32; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break; default: decon_err("invalid bpp %d\n", var->bits_per_pixel); return -EINVAL; } if (decon->pdata->psr_mode == DECON_MIPI_COMMAND_MODE) { x = var->xres; y = var->yres; } else { x = var->xres + var->left_margin + var->right_margin + var->hsync_len; y = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; } hz = 1000000000000ULL; /* 1e12 picoseconds per second */ hz += (x * y) / 2; do_div(hz, x * y); /* divide by x * y with rounding */ hz += var->pixclock / 2; do_div(hz, var->pixclock); /* divide by pixclock with rounding */ win->fps = hz; decon_dbg("xres:%d, yres:%d, v_xres:%d, v_yres:%d, bpp:%d, %lldhz\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel, hz); return 0; }