static void tegra_dc_rgb_enable(struct tegra_dc *dc) { int i; u32 out_sel_pintable[ARRAY_SIZE(tegra_dc_rgb_enable_out_sel_pintable)]; tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, DC_CMD_DISPLAY_POWER_CONTROL); tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); if (dc->out->out_pins) { tegra_dc_set_out_pin_polars(dc, dc->out->out_pins, dc->out->n_out_pins); tegra_dc_write_table(dc, tegra_dc_rgb_enable_partial_pintable); } else { tegra_dc_write_table(dc, tegra_dc_rgb_enable_pintable); } memcpy(out_sel_pintable, tegra_dc_rgb_enable_out_sel_pintable, sizeof(tegra_dc_rgb_enable_out_sel_pintable)); if (dc->out && dc->out->out_sel_configs) { u8 *out_sels = dc->out->out_sel_configs; for (i = 0; i < dc->out->n_out_sel_configs; i++) { switch (out_sels[i]) { case TEGRA_PIN_OUT_CONFIG_SEL_LM1_M1: out_sel_pintable[5*2+1] = (out_sel_pintable[5*2+1] & ~PIN5_LM1_LCD_M1_OUTPUT_MASK) | PIN5_LM1_LCD_M1_OUTPUT_M1; break; case TEGRA_PIN_OUT_CONFIG_SEL_LM1_LD21: out_sel_pintable[5*2+1] = (out_sel_pintable[5*2+1] & ~PIN5_LM1_LCD_M1_OUTPUT_MASK) | PIN5_LM1_LCD_M1_OUTPUT_LD21; break; case TEGRA_PIN_OUT_CONFIG_SEL_LM1_PM1: out_sel_pintable[5*2+1] = (out_sel_pintable[5*2+1] & ~PIN5_LM1_LCD_M1_OUTPUT_MASK) | PIN5_LM1_LCD_M1_OUTPUT_PM1; break; default: dev_err(&dc->ndev->dev, "Invalid pin config[%d]: %d\n", i, out_sels[i]); break; } } } tegra_dc_write_table(dc, out_sel_pintable); /* Inform DC register updated */ tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); }
void tegra_dc_disable_crc(struct tegra_dc *dc) { tegra_dc_writel(dc, 0x0, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_io_end(dc); }
int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user, struct tegra_dc_ext_cursor *args) { struct tegra_dc_ext *ext = user->ext; struct tegra_dc *dc = ext->dc; u32 val; bool enable; int ret; mutex_lock(&ext->cursor.lock); if (ext->cursor.user != user) { ret = -EACCES; goto unlock; } if (!ext->enabled) { ret = -ENXIO; goto unlock; } enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE); mutex_lock(&dc->lock); tegra_dc_io_start(dc); tegra_dc_hold_dc_out(dc); val = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); if (!!(val & CURSOR_ENABLE) != enable) { val &= ~CURSOR_ENABLE; if (enable) val |= CURSOR_ENABLE; tegra_dc_writel(dc, val, DC_DISP_DISP_WIN_OPTIONS); } tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y), DC_DISP_CURSOR_POSITION); tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); /* TODO: need to sync here? hopefully can avoid this, but need to * figure out interaction w/ rest of GENERAL_ACT_REQ */ tegra_dc_release_dc_out(dc); tegra_dc_io_end(dc); mutex_unlock(&dc->lock); mutex_unlock(&ext->cursor.lock); return 0; unlock: mutex_unlock(&ext->cursor.lock); return ret; }
void tegra_dc_rgb_enable(struct tegra_dc *dc) { tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, DC_CMD_DISPLAY_POWER_CONTROL); tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); tegra_dc_write_table(dc, tegra_dc_rgb_enable_pintable); }
void tegra_dc_enable_crc(struct tegra_dc *dc) { u32 val; tegra_dc_io_start(dc); val = CRC_ALWAYS_ENABLE | CRC_INPUT_DATA_ACTIVE_DATA | CRC_ENABLE_ENABLE; tegra_dc_writel(dc, val, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); }
void tegra_dc_disable_crc(struct tegra_dc *dc) { mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); tegra_dc_writel(dc, 0x0, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_io_end(dc); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }
static void tegra_dc_reset_worker(struct work_struct *work) { struct tegra_dc *dc = container_of(work, struct tegra_dc, reset_work); unsigned long val = 0; mutex_lock(&shared_lock); dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n"); tegra_dc_ext_disable(dc->ext); mutex_lock(&dc->lock); if (dc->enabled == false) goto unlock; dc->enabled = false; /* * off host read bus */ val = tegra_dc_readl(dc, DC_CMD_CONT_SYNCPT_VSYNC); val &= ~(0x00000100); tegra_dc_writel(dc, val, DC_CMD_CONT_SYNCPT_VSYNC); /* * set DC to STOP mode */ tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); msleep(10); _tegra_dc_controller_disable(dc); /* _tegra_dc_controller_reset_enable deasserts reset */ _tegra_dc_controller_reset_enable(dc); dc->enabled = true; /* reopen host read bus */ val = tegra_dc_readl(dc, DC_CMD_CONT_SYNCPT_VSYNC); val &= ~(0x00000100); val |= 0x100; tegra_dc_writel(dc, val, DC_CMD_CONT_SYNCPT_VSYNC); unlock: mutex_unlock(&dc->lock); mutex_unlock(&shared_lock); trace_printk("%s:reset complete\n", dc->ndev->name); }
static void set_cursor_image_hw(struct tegra_dc *dc, struct tegra_dc_ext_cursor_image *args, dma_addr_t phys_addr) { unsigned long val; int clip_win; tegra_dc_writel(dc, CURSOR_COLOR(args->foreground.r, args->foreground.g, args->foreground.b), DC_DISP_CURSOR_FOREGROUND); tegra_dc_writel(dc, CURSOR_COLOR(args->background.r, args->background.g, args->background.b), DC_DISP_CURSOR_BACKGROUND); BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK); switch (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(args->flags)) { case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64: val = CURSOR_SIZE_64; break; case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128: val = CURSOR_SIZE_128; break; case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256: val = CURSOR_SIZE_256; break; default: val = 0; } /* Get the cursor clip window number */ clip_win = CURSOR_CLIP_GET_WINDOW(tegra_dc_readl(dc, DC_DISP_CURSOR_START_ADDR)); val |= clip_win; tegra_dc_writel(dc, val | CURSOR_START_ADDR(((unsigned long) phys_addr)), DC_DISP_CURSOR_START_ADDR); if (args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_RGBA_NORMAL) tegra_dc_writel(dc, CURSOR_MODE_SELECT(1), DC_DISP_BLEND_CURSOR_CONTROL); else tegra_dc_writel(dc, CURSOR_MODE_SELECT(0), DC_DISP_BLEND_CURSOR_CONTROL); }
static irqreturn_t tegra_dc_irq(int irq, void *ptr) { #ifndef CONFIG_TEGRA_FPGA_PLATFORM struct tegra_dc *dc = ptr; unsigned long status; unsigned long underflow_mask; u32 val; if (!nvhost_module_powered_ext(nvhost_get_parent(dc->ndev))) { WARN(1, "IRQ when DC not powered!\n"); tegra_dc_io_start(dc); status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); tegra_dc_writel(dc, status, DC_CMD_INT_STATUS); tegra_dc_io_end(dc); return IRQ_HANDLED; } /* clear all status flags except underflow, save those for the worker */ status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); tegra_dc_writel(dc, status & ~ALL_UF_INT, DC_CMD_INT_STATUS); val = tegra_dc_readl(dc, DC_CMD_INT_MASK); tegra_dc_writel(dc, val & ~ALL_UF_INT, DC_CMD_INT_MASK); /* * Overlays can get thier internal state corrupted during and underflow * condition. The only way to fix this state is to reset the DC. * if we get 4 consecutive frames with underflows, assume we're * hosed and reset. */ underflow_mask = status & ALL_UF_INT; /* Check underflow */ if (underflow_mask) { dc->underflow_mask |= underflow_mask; schedule_delayed_work(&dc->underflow_work, msecs_to_jiffies(1)); } if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) tegra_dc_one_shot_irq(dc, status); else tegra_dc_continuous_irq(dc, status); return IRQ_HANDLED; #else /* CONFIG_TEGRA_FPGA_PLATFORM */ return IRQ_NONE; #endif /* !CONFIG_TEGRA_FPGA_PLATFORM */ }
/* Periodic update */ bool nvsd_update_brightness(struct tegra_dc *dc) { u32 val = 0; int cur_sd_brightness; if (sd_brightness) { if (atomic_read(&man_k_until_blank)) { val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); val &= ~SD_CORRECTION_MODE_MAN; tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); atomic_set(&man_k_until_blank, 0); } cur_sd_brightness = atomic_read(sd_brightness); /* read brightness value */ val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL); val = SD_BLC_BRIGHTNESS(val); if (val != (u32)cur_sd_brightness) { /* set brightness value and note the update */ atomic_set(sd_brightness, (int)val); return true; } } /* No update needed. */ return false; }
static void tegra_dc_set_scaling_filter(struct tegra_dc *dc) { unsigned i; unsigned v0 = 128; unsigned v1 = 0; /* linear horizontal and vertical filters */ for (i = 0; i < 16; i++) { tegra_dc_writel(dc, (v1 << 16) | (v0 << 8), DC_WIN_H_FILTER_P(i)); tegra_dc_writel(dc, v0, DC_WIN_V_FILTER_P(i)); v0 -= 8; v1 += 8; } }
void tegra_dc_enable_crc(struct tegra_dc *dc) { u32 val; mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); tegra_dc_io_start(dc); val = CRC_ALWAYS_ENABLE | CRC_INPUT_DATA_ACTIVE_DATA | CRC_ENABLE_ENABLE; tegra_dc_writel(dc, val, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }
static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr) { struct tegra_dc_win *win = &dc->windows[win_idx]; mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return -EFAULT; } if (fbovr > 0) win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE; else if (fbovr == 0) win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE; if (!tegra_dc_loop_lut(dc, win, tegra_dc_lut_isdefaults_lambda)) win->ppflags |= TEGRA_WIN_PPFLAG_CP_ENABLE; else win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_ENABLE; tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx, DC_CMD_DISPLAY_WINDOW_HEADER); tegra_dc_set_lut(dc, win); mutex_unlock(&dc->lock); tegra_dc_update_windows(&win, 1); return 0; }
static void tegra_dsi_set_dc_clk(struct tegra_dc *dc, struct tegra_dc_dsi_data *dsi) { u32 shift_clk_div; u32 val; if (dsi->info.video_burst_mode == TEGRA_DSI_VIDEO_NONE_BURST_MODE || dsi->info.video_burst_mode == TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END) shift_clk_div = NUMOF_BIT_PER_BYTE * dsi->pixel_scaler_mul / (dsi->pixel_scaler_div * dsi->info.n_data_lanes) - 2; else shift_clk_div = (dsi->current_dsi_clk_khz * 2 + dsi->default_hs_clk_khz - 1) / (dsi->default_hs_clk_khz) - 2; #ifdef CONFIG_TEGRA_FPGA_PLATFORM shift_clk_div = 1; #endif /* TODO: find out if PCD3 option is required */ val = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(shift_clk_div); tegra_dc_writel(dc, val, DC_DISP_DISP_CLOCK_CONTROL); clk_enable(dsi->dc_clk); }
static void tegra_dc_blend_sequential(struct tegra_dc *dc, struct tegra_dc_blend *blend) { int i; tegra_dc_io_start(dc); for (i = 0; i < DC_N_WINDOWS; i++) { if (!tegra_dc_feature_is_gen2_blender(dc, i)) continue; tegra_dc_writel(dc, WINDOW_A_SELECT << i, DC_CMD_DISPLAY_WINDOW_HEADER); if (blend->flags[i] & TEGRA_WIN_FLAG_BLEND_COVERAGE) { tegra_dc_writel(dc, WIN_K1(0xff) | WIN_K2(0xff) | WIN_BLEND_ENABLE, DC_WINBUF_BLEND_LAYER_CONTROL); tegra_dc_writel(dc, WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_SRC | WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_SRC | WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 | WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO, DC_WINBUF_BLEND_MATCH_SELECT); tegra_dc_writel(dc, WIN_ALPHA_1BIT_WEIGHT0(0) | WIN_ALPHA_1BIT_WEIGHT1(0xff), DC_WINBUF_BLEND_ALPHA_1BIT); } else if (blend->flags[i] & TEGRA_WIN_FLAG_BLEND_PREMULT) { tegra_dc_writel(dc, WIN_K1(0xff) | WIN_K2(0xff) | WIN_BLEND_ENABLE, DC_WINBUF_BLEND_LAYER_CONTROL); tegra_dc_writel(dc, WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 | WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1 | WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 | WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO, DC_WINBUF_BLEND_MATCH_SELECT); tegra_dc_writel(dc, WIN_ALPHA_1BIT_WEIGHT0(0) | WIN_ALPHA_1BIT_WEIGHT1(0xff), DC_WINBUF_BLEND_ALPHA_1BIT); } else { tegra_dc_writel(dc, WIN_BLEND_BYPASS, DC_WINBUF_BLEND_LAYER_CONTROL); } } tegra_dc_io_end(dc); }
static void tegra_dc_rgb_disable(struct tegra_dc *dc) { tegra_dc_io_start(dc); tegra_dc_writel(dc, 0x00000000, DC_CMD_DISPLAY_POWER_CONTROL); tegra_dc_write_table(dc, tegra_dc_rgb_disable_pintable); tegra_dc_io_end(dc); }
static void tegra_dsi_stop_dc_stream(struct tegra_dc *dc, struct tegra_dc_dsi_data *dsi) { /* * TODO: It is possible that we are in the middle of video stream, * Add code to wait for vsync and then stop DC from sending data to dsi */ tegra_dc_writel(dc, 0, DC_DISP_DISP_WIN_OPTIONS); }
static bool _tegra_dc_controller_enable(struct tegra_dc *dc) { int failed_init = 0; if (dc->out->enable) dc->out->enable(); tegra_dc_setup_clk(dc, dc->clk); tegra_dc_clk_enable(dc); /* do not accept interrupts during initialization */ tegra_dc_writel(dc, 0, DC_CMD_INT_MASK); enable_dc_irq(dc->irq); failed_init = tegra_dc_init(dc); if (failed_init) { tegra_dc_writel(dc, 0, DC_CMD_INT_MASK); disable_irq(dc->irq); tegra_dc_clear_bandwidth(dc); tegra_dc_clk_disable(dc); if (dc->out && dc->out->disable) dc->out->disable(); return false; } if (dc->out_ops && dc->out_ops->enable) dc->out_ops->enable(dc); /* force a full blending update */ dc->blend.z[0] = -1; tegra_dc_ext_enable(dc->ext); trace_printk("%s:enable\n", dc->ndev->name); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); if (dc->out->postpoweron) dc->out->postpoweron(); return true; }
void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc) { tegra_dc_writel(dc, csc->yof, DC_WIN_CSC_YOF); tegra_dc_writel(dc, csc->kyrgb, DC_WIN_CSC_KYRGB); tegra_dc_writel(dc, csc->kur, DC_WIN_CSC_KUR); tegra_dc_writel(dc, csc->kvr, DC_WIN_CSC_KVR); tegra_dc_writel(dc, csc->kug, DC_WIN_CSC_KUG); tegra_dc_writel(dc, csc->kvg, DC_WIN_CSC_KVG); tegra_dc_writel(dc, csc->kub, DC_WIN_CSC_KUB); tegra_dc_writel(dc, csc->kvb, DC_WIN_CSC_KVB); }
int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable) { tegra_dc_writel(dc, FRAME_END_INT, DC_CMD_INT_STATUS); if (enable) { atomic_inc(&frame_end_ref); tegra_dc_unmask_interrupt(dc, FRAME_END_INT); } else if (!atomic_dec_return(&frame_end_ref)) tegra_dc_mask_interrupt(dc, FRAME_END_INT); return 0; }
/* handle the commands that may be invoked for phase_in_settings */ static void nvsd_cmd_handler(struct tegra_dc_sd_settings *settings, struct tegra_dc *dc) { u32 val; u8 bw_idx, bw; if (settings->cmd & ENABLE) { settings->phase_settings_step++; if (settings->phase_settings_step >= settings->num_phase_in_steps) settings->cmd &= ~ENABLE; nvsd_phase_in_luts(settings, dc); } if (settings->cmd & DISABLE) { settings->phase_settings_step--; nvsd_phase_in_luts(settings, dc); if (settings->phase_settings_step == 0) { /* finish up aggressiveness phase in */ if (settings->cmd & AGG_CHG) settings->aggressiveness = settings->final_agg; settings->cmd = NO_CMD; settings->enable = 0; nvsd_init(dc, settings); } } if (settings->cmd & AGG_CHG) { if (settings->aggressiveness == settings->final_agg) settings->cmd &= ~AGG_CHG; if ((settings->cur_agg_step++ & (STEPS_PER_AGG_CHG - 1)) == 0) { settings->final_agg > settings->aggressiveness ? settings->aggressiveness++ : settings->aggressiveness--; /* Update aggressiveness value in HW */ val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); val &= ~SD_AGGRESSIVENESS(0x7); val |= SD_AGGRESSIVENESS(settings->aggressiveness); /* Adjust bin_width for automatic setting */ if (settings->bin_width == -1) { bw_idx = nvsd_get_bw_idx(settings); bw = bw_idx << 3; val &= ~SD_BIN_WIDTH_MASK; val |= bw; } tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); nvsd_phase_in_luts(settings, dc); } } }
static bool nvsd_phase_in_adjustments(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings) { u8 step, cur_sd_brightness; u16 target_k, cur_k; u32 man_k, val; cur_sd_brightness = atomic_read(_sd_brightness); target_k = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); target_k = SD_HW_K_R(target_k); cur_k = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES); cur_k = SD_HW_K_R(cur_k); /* read brightness value */ val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL); val = SD_BLC_BRIGHTNESS(val); step = settings->phase_adj_step; if (cur_sd_brightness != val || target_k != cur_k) { if (!step) step = ADJ_PHASE_STEP; /* Phase in Backlight and Pixel K every ADJ_PHASE_STEP frames*/ if ((step-- & ADJ_PHASE_STEP) == ADJ_PHASE_STEP) { if (val != cur_sd_brightness) { val > cur_sd_brightness ? (cur_sd_brightness++) : (cur_sd_brightness--); } if (target_k != cur_k) { if (target_k > cur_k) cur_k += K_STEP; else cur_k -= K_STEP; } /* Set manual k value */ man_k = SD_MAN_K_R(cur_k) | SD_MAN_K_G(cur_k) | SD_MAN_K_B(cur_k); tegra_dc_io_start(dc); tegra_dc_writel(dc, man_k, DC_DISP_SD_MAN_K_VALUES); tegra_dc_io_end(dc); /* Set manual brightness value */ atomic_set(_sd_brightness, cur_sd_brightness); } settings->phase_adj_step = step; return true; } else return false; }
/* get the stride size of a window. * return: stride size in bytes for window win. or 0 if unavailble. */ int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win) { u32 stride; if (!dc->enabled) return 0; BUG_ON(win > DC_N_WINDOWS); tegra_dc_writel(dc, WINDOW_A_SELECT << win, DC_CMD_DISPLAY_WINDOW_HEADER); stride = tegra_dc_readl(dc, DC_WIN_LINE_STRIDE); return GET_LINE_STRIDE(stride); }
static void _tegra_dc_controller_disable(struct tegra_dc *dc) { unsigned i; if (dc->out && dc->out->prepoweroff) dc->out->prepoweroff(); if (dc->out_ops && dc->out_ops->disable) dc->out_ops->disable(dc); tegra_dc_writel(dc, 0, DC_CMD_INT_MASK); tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE); disable_irq(dc->irq); tegra_dc_clear_bandwidth(dc); tegra_dc_clk_disable(dc); if (dc->out && dc->out->disable) dc->out->disable(); for (i = 0; i < dc->n_windows; i++) { struct tegra_dc_win *w = &dc->windows[i]; /* reset window bandwidth */ w->bandwidth = 0; w->new_bandwidth = 0; /* disable windows */ w->flags &= ~TEGRA_WIN_FLAG_ENABLED; /* flush any pending syncpt waits */ while (dc->syncpt[i].min < dc->syncpt[i].max) { trace_printk("%s:syncpt flush id=%d\n", dc->ndev->name, dc->syncpt[i].id); dc->syncpt[i].min++; nvhost_syncpt_cpu_incr_ext(dc->ndev, dc->syncpt[i].id); } } trace_printk("%s:disabled\n", dc->ndev->name); }
void tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg) { unsigned int ctrl; unsigned long out_sel; unsigned long cmd_state; mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return; } tegra_dc_hold_dc_out(dc); ctrl = ((cfg->period << PM_PERIOD_SHIFT) | (cfg->clk_div << PM_CLK_DIVIDER_SHIFT) | cfg->clk_select); /* The new value should be effected immediately */ cmd_state = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); tegra_dc_writel(dc, (cmd_state | (1 << 2)), DC_CMD_STATE_ACCESS); switch (cfg->which_pwm) { case TEGRA_PWM_PM0: /* Select the LM0 on PM0 */ out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5); out_sel &= ~(7 << 0); out_sel |= (3 << 0); tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5); tegra_dc_writel(dc, ctrl, DC_COM_PM0_CONTROL); tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM0_DUTY_CYCLE); break; case TEGRA_PWM_PM1: /* Select the LM1 on PM1 */ out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5); out_sel &= ~(7 << 4); out_sel |= (3 << 4); tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5); tegra_dc_writel(dc, ctrl, DC_COM_PM1_CONTROL); tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM1_DUTY_CYCLE); break; default: dev_err(&dc->ndev->dev, "Error: Need which_pwm\n"); break; } tegra_dc_writel(dc, cmd_state, DC_CMD_STATE_ACCESS); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }
static void tegra_dc_blend_parallel(struct tegra_dc *dc, struct tegra_dc_blend *blend) { int win_num = dc->gen1_blend_num; unsigned long mask = BIT(win_num) - 1; tegra_dc_io_start(dc); while (mask) { int idx = get_topmost_window(blend->z, &mask, win_num); tegra_dc_writel(dc, WINDOW_A_SELECT << idx, DC_CMD_DISPLAY_WINDOW_HEADER); tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff), DC_WIN_BLEND_NOKEY); tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff), DC_WIN_BLEND_1WIN); tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0, win_num), DC_WIN_BLEND_2WIN_X); tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1, win_num), DC_WIN_BLEND_2WIN_Y); tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags, win_num), DC_WIN_BLEND_3WIN_XY); } tegra_dc_io_end(dc); }
void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win *win) { unsigned long val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); tegra_dc_loop_lut(dc, win, tegra_dc_set_lut_setreg_lambda); if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE) val |= CP_ENABLE; else val &= ~CP_ENABLE; tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS); }
static void set_cursor_image_hw(struct tegra_dc *dc, struct tegra_dc_ext_cursor_image *args, dma_addr_t phys_addr) { tegra_dc_writel(dc, CURSOR_COLOR(args->foreground.r, args->foreground.g, args->foreground.b), DC_DISP_CURSOR_FOREGROUND); tegra_dc_writel(dc, CURSOR_COLOR(args->background.r, args->background.g, args->background.b), DC_DISP_CURSOR_BACKGROUND); BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK); tegra_dc_writel(dc, CURSOR_START_ADDR(((unsigned long) phys_addr)) | ((args->flags & TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) ? CURSOR_SIZE_64 : 0), DC_DISP_CURSOR_START_ADDR); }
void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable) { #if 0 /* underflow interrupt is already enabled by dc reset worker */ u32 val; if (dc->enabled) { val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE); if (enable) val |= (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT); else val &= ~(WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT); tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE); } #endif }
/* phase in the luts based on the current and max step */ static void nvsd_phase_in_luts(struct tegra_dc_sd_settings *settings, struct tegra_dc *dc) { u32 val; u8 bw_idx; int i; u16 phase_settings_step = settings->phase_settings_step; u16 num_phase_in_steps = settings->num_phase_in_steps; bw_idx = nvsd_get_bw_idx(settings); /* Phase in Final LUT */ for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) { val = SD_LUT_R((settings->lut[bw_idx][i].r * phase_settings_step)/num_phase_in_steps) | SD_LUT_G((settings->lut[bw_idx][i].g * phase_settings_step)/num_phase_in_steps) | SD_LUT_B((settings->lut[bw_idx][i].b * phase_settings_step)/num_phase_in_steps); tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i)); } /* Phase in Final BLTF */ for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) { val = SD_BL_TF_POINT_0(255-((255-settings->bltf[bw_idx][i][0]) * phase_settings_step)/num_phase_in_steps) | SD_BL_TF_POINT_1(255-((255-settings->bltf[bw_idx][i][1]) * phase_settings_step)/num_phase_in_steps) | SD_BL_TF_POINT_2(255-((255-settings->bltf[bw_idx][i][2]) * phase_settings_step)/num_phase_in_steps) | SD_BL_TF_POINT_3(255-((255-settings->bltf[bw_idx][i][3]) * phase_settings_step)/num_phase_in_steps); tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i)); } }