int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode) { unsigned long val; unsigned long rate; unsigned long div; unsigned long pclk; print_mode(dc, mode, __func__); /* use default EMC rate when switching modes */ dc->new_emc_clk_rate = tegra_dc_get_default_emc_clk_rate(dc); tegra_dc_program_bandwidth(dc, true); tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16), DC_DISP_REF_TO_SYNC); tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16), DC_DISP_SYNC_WIDTH); tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16), DC_DISP_BACK_PORCH); tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16), DC_DISP_DISP_ACTIVE); tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16), DC_DISP_FRONT_PORCH); tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL, DC_DISP_DATA_ENABLE_OPTIONS); /* TODO: MIPI/CRT/HDMI clock cals */ val = 0; if (!(dc->out->type == TEGRA_DC_OUT_DSI || dc->out->type == TEGRA_DC_OUT_HDMI)) { val = DISP_DATA_FORMAT_DF1P1C; if (dc->out->align == TEGRA_DC_ALIGN_MSB) val |= DISP_DATA_ALIGNMENT_MSB; else val |= DISP_DATA_ALIGNMENT_LSB; if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE) val |= DISP_DATA_ORDER_RED_BLUE; else val |= DISP_DATA_ORDER_BLUE_RED; } tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL); rate = tegra_dc_clk_get_rate(dc); pclk = tegra_dc_pclk_round_rate(dc, mode->pclk); if (pclk < (mode->pclk / 100 * 99) || pclk > (mode->pclk / 100 * 109)) { dev_err(&dc->ndev->dev, "can't divide %ld clock to %d -1/+9%% %ld %d %d\n", rate, mode->pclk, pclk, (mode->pclk / 100 * 99), (mode->pclk / 100 * 109)); return -EINVAL; } div = (rate * 2 / pclk) - 2; tegra_dc_writel(dc, 0x00010001, DC_DISP_SHIFT_CLOCK_OPTIONS); tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div), DC_DISP_DISP_CLOCK_CONTROL); #ifdef CONFIG_SWITCH switch_set_state(&dc->modeset_switch, (mode->h_active << 16) | mode->v_active); #endif tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); dc->mode_dirty = false; trace_display_mode(dc, &dc->mode); return 0; }
int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode) { unsigned long val; unsigned long rate; unsigned long div; unsigned long pclk; unsigned long v_back_porch; unsigned long v_front_porch; unsigned long v_sync_width; unsigned long v_active; v_back_porch = mode->v_back_porch; v_front_porch = mode->v_front_porch; v_sync_width = mode->v_sync_width; v_active = mode->v_active; if (mode->vmode == FB_VMODE_INTERLACED) { v_back_porch /= 2; v_front_porch /= 2; v_sync_width /= 2; v_active /= 2; } print_mode(dc, mode, __func__); /* use default EMC rate when switching modes */ #ifdef CONFIG_TEGRA_ISOMGR dc->new_bw_kbps = tegra_dc_calc_min_bandwidth(dc); #else dc->new_bw_kbps = tegra_emc_freq_req_to_bw( tegra_dc_get_default_emc_clk_rate(dc) / 1000); #endif tegra_dc_program_bandwidth(dc, true); tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16), DC_DISP_REF_TO_SYNC); tegra_dc_writel(dc, mode->h_sync_width | (v_sync_width << 16), DC_DISP_SYNC_WIDTH); if ((dc->out->type == TEGRA_DC_OUT_DP) || (dc->out->type == TEGRA_DC_OUT_LVDS)) { tegra_dc_writel(dc, mode->h_back_porch | ((v_back_porch - mode->v_ref_to_sync) << 16), DC_DISP_BACK_PORCH); tegra_dc_writel(dc, mode->h_front_porch | ((v_front_porch + mode->v_ref_to_sync) << 16), DC_DISP_FRONT_PORCH); } else { tegra_dc_writel(dc, mode->h_back_porch | (v_back_porch << 16), DC_DISP_BACK_PORCH); tegra_dc_writel(dc, mode->h_front_porch | (v_front_porch << 16), DC_DISP_FRONT_PORCH); } tegra_dc_writel(dc, mode->h_active | (v_active << 16), DC_DISP_DISP_ACTIVE); #if defined(CONFIG_TEGRA_DC_INTERLACE) if (mode->vmode == FB_VMODE_INTERLACED) tegra_dc_writel(dc, INTERLACE_MODE_ENABLE | INTERLACE_START_FIELD_1 | INTERLACE_STATUS_FIELD_1, DC_DISP_INTERLACE_CONTROL); else tegra_dc_writel(dc, INTERLACE_MODE_DISABLE, DC_DISP_INTERLACE_CONTROL); if (mode->vmode == FB_VMODE_INTERLACED) { tegra_dc_writel(dc, (mode->h_ref_to_sync | ((mode->h_sync_width + mode->h_back_porch + mode->h_active + mode->h_front_porch) >> 1) << 16), DC_DISP_INTERLACE_FIELD2_REF_TO_SYNC); tegra_dc_writel(dc, mode->h_sync_width | (v_sync_width << 16), DC_DISP_INTERLACE_FIELD2_SYNC_WIDTH); tegra_dc_writel(dc, mode->h_back_porch | ((v_back_porch + 1) << 16), DC_DISP_INTERLACE_FIELD2_BACK_PORCH); tegra_dc_writel(dc, mode->h_active | (v_active << 16), DC_DISP_INTERLACE_FIELD2_DISP_ACTIVE); tegra_dc_writel(dc, mode->h_front_porch | (v_front_porch << 16), DC_DISP_INTERLACE_FIELD2_FRONT_PORCH); }