#define TEGRA_MAX_DC 2
#if defined(CONFIG_ARCH_TEGRA_14x_SOC)
-#define DC_N_WINDOWS 5
+#define DC_N_WINDOWS 6
#elif defined(CONFIG_ARCH_TEGRA_12x_SOC)
-#define DC_N_WINDOWS 4
+#define DC_N_WINDOWS 5
#else
#define DC_N_WINDOWS 3
#endif
#define TEGRA_WIN_FLAG_SCAN_COLUMN (1 << 9)
#define TEGRA_WIN_FLAG_INTERLACE (1 << 10)
#define TEGRA_WIN_FLAG_FB (1 << 11)
+#define TEGRA_WIN_FLAG_INVALID (1 << 31) /* window does not exist. */
#define TEGRA_WIN_BLEND_FLAGS_MASK \
(TEGRA_WIN_FLAG_BLEND_PREMULT | TEGRA_WIN_FLAG_BLEND_COVERAGE)
unsigned int num_active_internal_wins = 0;
int i = 0;
- for (i = 0; i < DC_N_WINDOWS; i++) {
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
struct tegra_dc_win *curr_win = &dc->windows[i];
enum tegra_la_id curr_win_la_id =
la_id_tab[dc->ndev->id][curr_win->idx];
unsigned int num_active_external_wins = 0;
int i = 0;
- for (i = 0; i < DC_N_WINDOWS; i++) {
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
struct tegra_dc_win *curr_win = &dc->windows[i];
enum tegra_la_id curr_win_la_id =
la_id_tab[dc->ndev->id][curr_win->idx];
if (is_internal_win(la_id)) {
int i = 0;
- for (i = 0; i < DC_N_WINDOWS; i++) {
+
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
struct tegra_dc_win *curr_win = &dc->windows[i];
enum tegra_la_id curr_win_la_id =
la_id_tab[dc->ndev->id][curr_win->idx];
}
} else {
int i = 0;
- for (i = 0; i < DC_N_WINDOWS; i++) {
+
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
struct tegra_dc_win *curr_win = &dc->windows[i];
enum tegra_la_id curr_win_la_id =
la_id_tab[dc->ndev->id][curr_win->idx];
dc->bw_kbps = dc->new_bw_kbps;
}
- for (i = 0; i < DC_N_WINDOWS; i++) {
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
struct tegra_dc_win *w = &dc->windows[i];
if ((use_new || w->bandwidth != w->new_bandwidth) &&
unsigned long new_rate;
struct tegra_dc_win *windows[DC_N_WINDOWS];
unsigned i;
+ unsigned len;
if (!use_dynamic_emc)
return 0;
- for (i = 0; i < DC_N_WINDOWS; i++)
- windows[i] = &dc->windows[i];
+ for (i = 0, len = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *win = tegra_dc_get_window(dc, i);
+ if (win)
+ windows[len++] = win;
+ }
#ifdef CONFIG_TEGRA_ISOMGR
- new_rate = tegra_dc_get_bandwidth(windows, DC_N_WINDOWS);
+ new_rate = tegra_dc_get_bandwidth(windows, len);
#else
if (tegra_dc_has_multiple_dc())
new_rate = ULONG_MAX;
else
- new_rate = tegra_dc_get_bandwidth(windows, DC_N_WINDOWS);
+ new_rate = tegra_dc_get_bandwidth(windows, len);
#endif
dc->new_bw_kbps = new_rate;
struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
{
- if (win >= dc->n_windows)
+ if (win >= DC_N_WINDOWS || !test_bit(win, &dc->valid_windows))
return NULL;
return &dc->windows[win];
static void tegra_dc_underflow_handler(struct tegra_dc *dc)
{
+ const u32 masks[] = {
+ WIN_A_UF_INT,
+ WIN_B_UF_INT,
+ WIN_C_UF_INT,
+#if defined(CONFIG_ARCH_TEGRA_14x_SOC) || defined(CONFIG_ARCH_TEGRA_12x_SOC)
+ WIN_D_UF_INT,
+ HC_UF_INT,
+ WIN_T_UF_INT,
+#endif
+ };
int i;
dc->stats.underflows++;
#endif
/* Check for any underflow reset conditions */
- for (i = 0; i < DC_N_WINDOWS; i++) {
- u32 masks[] = {
- WIN_A_UF_INT,
- WIN_B_UF_INT,
- WIN_C_UF_INT,
-#if defined(CONFIG_ARCH_TEGRA_14x_SOC) || defined(CONFIG_ARCH_TEGRA_12x_SOC)
- WIN_D_UF_INT,
- HC_UF_INT,
- WIN_T_UF_INT,
-#endif
- };
-
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
if (WARN_ONCE(i >= ARRAY_SIZE(masks),
"underflow stats unsupported"))
break; /* bail if the table above is missing entries */
}
#endif
tegra_dc_set_color_control(dc);
- for (i = 0; i < DC_N_WINDOWS; i++) {
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
struct tegra_dc_win *win = &dc->windows[i];
tegra_dc_writel(dc, WINDOW_A_SELECT << i,
DC_CMD_DISPLAY_WINDOW_HEADER);
struct tegra_dc_win *dcwins[DC_N_WINDOWS];
unsigned i;
- for (i = 0; i < DC_N_WINDOWS; i++) {
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
dcwins[i] = tegra_dc_get_window(dc, i);
+ if (!dcwins[i])
+ continue;
dcwins[i]->flags &= ~TEGRA_WIN_FLAG_ENABLED;
}
tegra_dc_init_lut_defaults(&dc->fb_lut);
dc->n_windows = DC_N_WINDOWS;
- for (i = 0; i < dc->n_windows; i++) {
+ for (i = 0; i < DC_N_WINDOWS; i++) {
struct tegra_dc_win *win = &dc->windows[i];
struct tegra_dc_win *tmp_win = &dc->tmp_wins[i];
+ if (!test_bit(i, &dc->valid_windows))
+ win->flags |= TEGRA_WIN_FLAG_INVALID;
win->idx = i;
win->dc = dc;
tmp_win->idx = i;
u32 vblank_syncpt;
u32 win_syncpt[DC_N_WINDOWS];
- u32 valid_windows;
+ unsigned long int valid_windows;
unsigned long underflow_mask;
struct work_struct reset_work;
struct tegra_dc_ext_win *win;
int ret = 0;
- if (n >= DC_N_WINDOWS)
+ if ((n >= DC_N_WINDOWS) || !(ext->dc->valid_windows & BIT(n)))
return -EINVAL;
win = &ext->win[n];
s64 head_timestamp = 0;
int j = 0;
- if (index < 0)
+ if (index < 0 || !test_bit(index, &ext->dc->valid_windows))
continue;
win = tegra_dc_get_window(ext->dc, index);
+ if (!win)
+ continue;
ext_win = &ext->win[index];
if (!(atomic_dec_and_test(&ext_win->nr_pending_flips)) &&
struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
int index = flip_win->attr.index;
- if (index < 0)
+ if (index < 0 ||
+ !test_bit(index, &ext->dc->valid_windows))
continue;
tegra_dc_incr_syncpt_min(ext->dc, index,
for (i = 0; i < win_num; i++) {
int index = win[i].index;
- if (index < 0)
+ if (index < 0 || !test_bit(index, &ext->dc->valid_windows))
continue;
idx_mask |= BIT(index);
for (i = 0; i < win_num; i++) {
int index = win[i].index;
- if (index < 0)
+ if (index < 0 || !test_bit(index, &ext->dc->valid_windows))
continue;
idx_mask |= BIT(index);
int win_num)
{
int i, used_windows = 0;
+ struct tegra_dc *dc = user->ext->dc;
if (win_num > DC_N_WINDOWS)
return -EINVAL;
if (index < 0)
continue;
- if (index >= DC_N_WINDOWS)
+ if (index >= DC_N_WINDOWS ||
+ !test_bit(index, &dc->valid_windows))
return -EINVAL;
if (used_windows & BIT(index))
bool *has_timestamp)
{
int i, ret;
+ struct tegra_dc *dc = user->ext->dc;
for (i = 0; i < win_num; i++) {
struct tegra_dc_ext_flip_win *flip_win = &flip_wins[i];
if (has_timestamp && timespec_to_ns(&flip_win->attr.timestamp))
*has_timestamp = true;
- if (index < 0)
+ if (index < 0 || !test_bit(index, &dc->valid_windows))
continue;
ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id,
int index = win[i].index;
struct tegra_dc_ext_win *ext_win;
- if (index < 0)
+ if (index < 0 || !test_bit(index, &ext->dc->valid_windows))
continue;
ext_win = &ext->win[index];
return -1;
for (i = 0; i < win_num; i++) {
+ int idx = wins[i].index;
+
ret = tegra_dc_ext_pin_window(user, wins[i].buff_id,
&handle, &phys_addr);
if (ret)
handle->sgt, DMA_TO_DEVICE);
dma_buf_put(handle->buf);
kfree(handle);
- tegra_dc_ext_set_windowattr_basic(&dc->tmp_wins[i],
+ tegra_dc_ext_set_windowattr_basic(&dc->tmp_wins[idx],
&wins[i]);
}
else {
dc->tmp_wins[i].flags = 0;
}
- dc_wins[i] = &dc->tmp_wins[i];
+ dc_wins[i] = &dc->tmp_wins[idx];
}
ret = tegra_dc_bandwidth_negotiate_bw(dc, dc_wins, win_num);
/* used by tegra_dc_probe() to detect hpd/hdmi status at boot */
static bool tegra_dc_hdmi_detect(struct tegra_dc *dc)
{
- int hdmi_state;
-
hdmi_state_machine_set_pending_hpd();
/* result isn't used by dc */
static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
{
- struct tegra_dc_win *win = &dc->windows[win_idx];
+ struct tegra_dc_win *win = tegra_dc_get_window(dc, win_idx);
+ if (!win)
+ return -EINVAL;
mutex_lock(&dc->lock);
tegra_dc_get(dc);
if (win_idx > -1)
return tegra_dc_update_winlut(dc, win_idx, fboveride);
- for (win_idx = 0; win_idx < DC_N_WINDOWS; win_idx++) {
+ for_each_set_bit(win_idx, &dc->valid_windows, DC_N_WINDOWS) {
int err = tegra_dc_update_winlut(dc, win_idx, fboveride);
if (err)
return err;
if (update_blend_seq)
tegra_dc_blend_sequential(dc, &dc->blend);
- for (i = 0; i < DC_N_WINDOWS; i++) {
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
if (!no_vsync)
dc->windows[i].dirty = 1;
update_mask |= WIN_A_ACT_REQ << i;
#endif
val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
- for (i = 0; i < DC_N_WINDOWS; i++) {
+ for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
if (tegra_platform_is_linsim()) {
/* FIXME: this is not needed when
the simulator clears WIN_x_UPDATE