Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright © 2006-2011 Intel Corporation |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify it |
| 5 | * under the terms and conditions of the GNU General Public License, |
| 6 | * version 2, as published by the Free Software Foundation. |
| 7 | * |
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT |
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 11 | * more details. |
| 12 | * |
| 13 | * You should have received a copy of the GNU General Public License along with |
| 14 | * this program; if not, write to the Free Software Foundation, Inc., |
| 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| 16 | * |
| 17 | * Authors: |
| 18 | * Eric Anholt <eric@anholt.net> |
| 19 | */ |
| 20 | |
| 21 | #include <linux/i2c.h> |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 22 | |
| 23 | #include <drm/drmP.h> |
| 24 | #include "framebuffer.h" |
| 25 | #include "psb_drv.h" |
| 26 | #include "psb_intel_drv.h" |
| 27 | #include "psb_intel_reg.h" |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 28 | #include "gma_display.h" |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 29 | #include "power.h" |
| 30 | |
Patrik Jakobsson | 4e6bb70 | 2013-03-13 23:24:08 +0100 | [diff] [blame] | 31 | #define INTEL_LIMIT_I9XX_SDVO_DAC 0 |
| 32 | #define INTEL_LIMIT_I9XX_LVDS 1 |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 33 | |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 34 | static const struct gma_limit_t psb_intel_limits[] = { |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 35 | { /* INTEL_LIMIT_I9XX_SDVO_DAC */ |
Patrik Jakobsson | 06da491 | 2013-03-14 00:14:06 +0100 | [diff] [blame] | 36 | .dot = {.min = 20000, .max = 400000}, |
| 37 | .vco = {.min = 1400000, .max = 2800000}, |
| 38 | .n = {.min = 1, .max = 6}, |
| 39 | .m = {.min = 70, .max = 120}, |
| 40 | .m1 = {.min = 8, .max = 18}, |
| 41 | .m2 = {.min = 3, .max = 7}, |
| 42 | .p = {.min = 5, .max = 80}, |
| 43 | .p1 = {.min = 1, .max = 8}, |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 44 | .p2 = {.dot_limit = 200000, .p2_slow = 10, .p2_fast = 5}, |
| 45 | .find_pll = gma_find_best_pll, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 46 | }, |
| 47 | { /* INTEL_LIMIT_I9XX_LVDS */ |
Patrik Jakobsson | 06da491 | 2013-03-14 00:14:06 +0100 | [diff] [blame] | 48 | .dot = {.min = 20000, .max = 400000}, |
| 49 | .vco = {.min = 1400000, .max = 2800000}, |
| 50 | .n = {.min = 1, .max = 6}, |
| 51 | .m = {.min = 70, .max = 120}, |
| 52 | .m1 = {.min = 8, .max = 18}, |
| 53 | .m2 = {.min = 3, .max = 7}, |
| 54 | .p = {.min = 7, .max = 98}, |
| 55 | .p1 = {.min = 1, .max = 8}, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 56 | /* The single-channel range is 25-112Mhz, and dual-channel |
| 57 | * is 80-224Mhz. Prefer single channel as much as possible. |
| 58 | */ |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 59 | .p2 = {.dot_limit = 112000, .p2_slow = 14, .p2_fast = 7}, |
| 60 | .find_pll = gma_find_best_pll, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 61 | }, |
| 62 | }; |
| 63 | |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 64 | static const struct gma_limit_t *psb_intel_limit(struct drm_crtc *crtc, |
| 65 | int refclk) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 66 | { |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 67 | const struct gma_limit_t *limit; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 68 | |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 69 | if (gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 70 | limit = &psb_intel_limits[INTEL_LIMIT_I9XX_LVDS]; |
| 71 | else |
| 72 | limit = &psb_intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; |
| 73 | return limit; |
| 74 | } |
| 75 | |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 76 | static void psb_intel_clock(int refclk, struct gma_clock_t *clock) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 77 | { |
| 78 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); |
| 79 | clock->p = clock->p1 * clock->p2; |
| 80 | clock->vco = refclk * clock->m / (clock->n + 2); |
| 81 | clock->dot = clock->vco / clock->p; |
| 82 | } |
| 83 | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 84 | /** |
| 85 | * Return the pipe currently connected to the panel fitter, |
| 86 | * or -1 if the panel fitter is not present or not in use |
| 87 | */ |
| 88 | static int psb_intel_panel_fitter_pipe(struct drm_device *dev) |
| 89 | { |
| 90 | u32 pfit_control; |
| 91 | |
| 92 | pfit_control = REG_READ(PFIT_CONTROL); |
| 93 | |
| 94 | /* See if the panel fitter is in use */ |
| 95 | if ((pfit_control & PFIT_ENABLE) == 0) |
| 96 | return -1; |
| 97 | /* Must be on PIPE 1 for PSB */ |
| 98 | return 1; |
| 99 | } |
| 100 | |
| 101 | static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, |
| 102 | struct drm_display_mode *mode, |
| 103 | struct drm_display_mode *adjusted_mode, |
| 104 | int x, int y, |
| 105 | struct drm_framebuffer *old_fb) |
| 106 | { |
| 107 | struct drm_device *dev = crtc->dev; |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 108 | struct drm_psb_private *dev_priv = dev->dev_private; |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 109 | struct gma_crtc *gma_crtc = to_gma_crtc(crtc); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 110 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 111 | int pipe = gma_crtc->pipe; |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 112 | const struct psb_offset *map = &dev_priv->regmap[pipe]; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 113 | int refclk; |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 114 | struct gma_clock_t clock; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 115 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; |
Kirill A. Shutemov | 2e33d6b | 2012-03-08 16:15:20 +0000 | [diff] [blame] | 116 | bool ok, is_sdvo = false; |
| 117 | bool is_lvds = false, is_tv = false; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 118 | struct drm_mode_config *mode_config = &dev->mode_config; |
| 119 | struct drm_connector *connector; |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 120 | const struct gma_limit_t *limit; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 121 | |
| 122 | /* No scan out no play */ |
Matt Roper | f4510a2 | 2014-04-01 15:22:40 -0700 | [diff] [blame] | 123 | if (crtc->primary->fb == NULL) { |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 124 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); |
| 125 | return 0; |
| 126 | } |
| 127 | |
| 128 | list_for_each_entry(connector, &mode_config->connector_list, head) { |
Patrik Jakobsson | 367e440 | 2013-07-22 17:45:26 +0200 | [diff] [blame] | 129 | struct gma_encoder *gma_encoder = gma_attached_encoder(connector); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 130 | |
| 131 | if (!connector->encoder |
| 132 | || connector->encoder->crtc != crtc) |
| 133 | continue; |
| 134 | |
Patrik Jakobsson | 367e440 | 2013-07-22 17:45:26 +0200 | [diff] [blame] | 135 | switch (gma_encoder->type) { |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 136 | case INTEL_OUTPUT_LVDS: |
| 137 | is_lvds = true; |
| 138 | break; |
| 139 | case INTEL_OUTPUT_SDVO: |
| 140 | is_sdvo = true; |
| 141 | break; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 142 | case INTEL_OUTPUT_TVOUT: |
| 143 | is_tv = true; |
| 144 | break; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 145 | } |
| 146 | } |
| 147 | |
| 148 | refclk = 96000; |
| 149 | |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 150 | limit = gma_crtc->clock_funcs->limit(crtc, refclk); |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 151 | |
| 152 | ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 153 | &clock); |
| 154 | if (!ok) { |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 155 | DRM_ERROR("Couldn't find PLL settings for mode! target: %d, actual: %d", |
| 156 | adjusted_mode->clock, clock.dot); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 157 | return 0; |
| 158 | } |
| 159 | |
| 160 | fp = clock.n << 16 | clock.m1 << 8 | clock.m2; |
| 161 | |
| 162 | dpll = DPLL_VGA_MODE_DIS; |
| 163 | if (is_lvds) { |
| 164 | dpll |= DPLLB_MODE_LVDS; |
| 165 | dpll |= DPLL_DVO_HIGH_SPEED; |
| 166 | } else |
| 167 | dpll |= DPLLB_MODE_DAC_SERIAL; |
| 168 | if (is_sdvo) { |
| 169 | int sdvo_pixel_multiply = |
| 170 | adjusted_mode->clock / mode->clock; |
| 171 | dpll |= DPLL_DVO_HIGH_SPEED; |
| 172 | dpll |= |
| 173 | (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; |
| 174 | } |
| 175 | |
| 176 | /* compute bitmask from p1 value */ |
| 177 | dpll |= (1 << (clock.p1 - 1)) << 16; |
| 178 | switch (clock.p2) { |
| 179 | case 5: |
| 180 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; |
| 181 | break; |
| 182 | case 7: |
| 183 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; |
| 184 | break; |
| 185 | case 10: |
| 186 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; |
| 187 | break; |
| 188 | case 14: |
| 189 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; |
| 190 | break; |
| 191 | } |
| 192 | |
| 193 | if (is_tv) { |
| 194 | /* XXX: just matching BIOS for now */ |
| 195 | /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ |
| 196 | dpll |= 3; |
| 197 | } |
| 198 | dpll |= PLL_REF_INPUT_DREFCLK; |
| 199 | |
| 200 | /* setup pipeconf */ |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 201 | pipeconf = REG_READ(map->conf); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 202 | |
| 203 | /* Set up the display plane register */ |
| 204 | dspcntr = DISPPLANE_GAMMA_ENABLE; |
| 205 | |
| 206 | if (pipe == 0) |
| 207 | dspcntr |= DISPPLANE_SEL_PIPE_A; |
| 208 | else |
| 209 | dspcntr |= DISPPLANE_SEL_PIPE_B; |
| 210 | |
| 211 | dspcntr |= DISPLAY_PLANE_ENABLE; |
| 212 | pipeconf |= PIPEACONF_ENABLE; |
| 213 | dpll |= DPLL_VCO_ENABLE; |
| 214 | |
| 215 | |
| 216 | /* Disable the panel fitter if it was on our pipe */ |
| 217 | if (psb_intel_panel_fitter_pipe(dev) == pipe) |
| 218 | REG_WRITE(PFIT_CONTROL, 0); |
| 219 | |
| 220 | drm_mode_debug_printmodeline(mode); |
| 221 | |
| 222 | if (dpll & DPLL_VCO_ENABLE) { |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 223 | REG_WRITE(map->fp0, fp); |
| 224 | REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE); |
| 225 | REG_READ(map->dpll); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 226 | udelay(150); |
| 227 | } |
| 228 | |
| 229 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. |
| 230 | * This is an exception to the general rule that mode_set doesn't turn |
| 231 | * things on. |
| 232 | */ |
| 233 | if (is_lvds) { |
| 234 | u32 lvds = REG_READ(LVDS); |
| 235 | |
| 236 | lvds &= ~LVDS_PIPEB_SELECT; |
| 237 | if (pipe == 1) |
| 238 | lvds |= LVDS_PIPEB_SELECT; |
| 239 | |
| 240 | lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; |
| 241 | /* Set the B0-B3 data pairs corresponding to |
| 242 | * whether we're going to |
| 243 | * set the DPLLs for dual-channel mode or not. |
| 244 | */ |
| 245 | lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); |
| 246 | if (clock.p2 == 7) |
| 247 | lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; |
| 248 | |
| 249 | /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) |
| 250 | * appropriately here, but we need to look more |
| 251 | * thoroughly into how panels behave in the two modes. |
| 252 | */ |
| 253 | |
| 254 | REG_WRITE(LVDS, lvds); |
| 255 | REG_READ(LVDS); |
| 256 | } |
| 257 | |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 258 | REG_WRITE(map->fp0, fp); |
| 259 | REG_WRITE(map->dpll, dpll); |
| 260 | REG_READ(map->dpll); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 261 | /* Wait for the clocks to stabilize. */ |
| 262 | udelay(150); |
| 263 | |
| 264 | /* write it again -- the BIOS does, after all */ |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 265 | REG_WRITE(map->dpll, dpll); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 266 | |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 267 | REG_READ(map->dpll); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 268 | /* Wait for the clocks to stabilize. */ |
| 269 | udelay(150); |
| 270 | |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 271 | REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 272 | ((adjusted_mode->crtc_htotal - 1) << 16)); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 273 | REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 274 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 275 | REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 276 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 277 | REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 278 | ((adjusted_mode->crtc_vtotal - 1) << 16)); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 279 | REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 280 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 281 | REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 282 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); |
| 283 | /* pipesrc and dspsize control the size that is scaled from, |
| 284 | * which should always be the user's requested size. |
| 285 | */ |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 286 | REG_WRITE(map->size, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 287 | ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 288 | REG_WRITE(map->pos, 0); |
| 289 | REG_WRITE(map->src, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 290 | ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 291 | REG_WRITE(map->conf, pipeconf); |
| 292 | REG_READ(map->conf); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 293 | |
Patrik Jakobsson | d1fa08f | 2013-07-10 01:20:19 +0200 | [diff] [blame] | 294 | gma_wait_for_vblank(dev); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 295 | |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 296 | REG_WRITE(map->cntr, dspcntr); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 297 | |
| 298 | /* Flush the plane changes */ |
| 299 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); |
| 300 | |
Patrik Jakobsson | d1fa08f | 2013-07-10 01:20:19 +0200 | [diff] [blame] | 301 | gma_wait_for_vblank(dev); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 302 | |
| 303 | return 0; |
| 304 | } |
| 305 | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 306 | /* Returns the clock of the currently programmed mode of the given pipe. */ |
| 307 | static int psb_intel_crtc_clock_get(struct drm_device *dev, |
| 308 | struct drm_crtc *crtc) |
| 309 | { |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 310 | struct gma_crtc *gma_crtc = to_gma_crtc(crtc); |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 311 | struct drm_psb_private *dev_priv = dev->dev_private; |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 312 | int pipe = gma_crtc->pipe; |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 313 | const struct psb_offset *map = &dev_priv->regmap[pipe]; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 314 | u32 dpll; |
| 315 | u32 fp; |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 316 | struct gma_clock_t clock; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 317 | bool is_lvds; |
Alan Cox | 6256304 | 2012-05-11 11:30:16 +0100 | [diff] [blame] | 318 | struct psb_pipe *p = &dev_priv->regs.pipe[pipe]; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 319 | |
| 320 | if (gma_power_begin(dev, false)) { |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 321 | dpll = REG_READ(map->dpll); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 322 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 323 | fp = REG_READ(map->fp0); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 324 | else |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 325 | fp = REG_READ(map->fp1); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 326 | is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN); |
| 327 | gma_power_end(dev); |
| 328 | } else { |
Alan Cox | 6256304 | 2012-05-11 11:30:16 +0100 | [diff] [blame] | 329 | dpll = p->dpll; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 330 | |
| 331 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) |
Alan Cox | 6256304 | 2012-05-11 11:30:16 +0100 | [diff] [blame] | 332 | fp = p->fp0; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 333 | else |
Alan Cox | 6256304 | 2012-05-11 11:30:16 +0100 | [diff] [blame] | 334 | fp = p->fp1; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 335 | |
Alan Cox | c6265ff | 2012-03-08 16:02:05 +0000 | [diff] [blame] | 336 | is_lvds = (pipe == 1) && (dev_priv->regs.psb.saveLVDS & |
Alan Cox | 648a8e3 | 2012-03-08 16:00:31 +0000 | [diff] [blame] | 337 | LVDS_PORT_EN); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 338 | } |
| 339 | |
| 340 | clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; |
| 341 | clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; |
| 342 | clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; |
| 343 | |
| 344 | if (is_lvds) { |
| 345 | clock.p1 = |
| 346 | ffs((dpll & |
| 347 | DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> |
| 348 | DPLL_FPA01_P1_POST_DIV_SHIFT); |
| 349 | clock.p2 = 14; |
| 350 | |
| 351 | if ((dpll & PLL_REF_INPUT_MASK) == |
| 352 | PLLB_REF_INPUT_SPREADSPECTRUMIN) { |
| 353 | /* XXX: might not be 66MHz */ |
Patrik Jakobsson | 1548060 | 2013-03-13 23:32:36 +0100 | [diff] [blame] | 354 | psb_intel_clock(66000, &clock); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 355 | } else |
Patrik Jakobsson | 1548060 | 2013-03-13 23:32:36 +0100 | [diff] [blame] | 356 | psb_intel_clock(48000, &clock); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 357 | } else { |
| 358 | if (dpll & PLL_P1_DIVIDE_BY_TWO) |
| 359 | clock.p1 = 2; |
| 360 | else { |
| 361 | clock.p1 = |
| 362 | ((dpll & |
| 363 | DPLL_FPA01_P1_POST_DIV_MASK_I830) >> |
| 364 | DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; |
| 365 | } |
| 366 | if (dpll & PLL_P2_DIVIDE_BY_4) |
| 367 | clock.p2 = 4; |
| 368 | else |
| 369 | clock.p2 = 2; |
| 370 | |
Patrik Jakobsson | 1548060 | 2013-03-13 23:32:36 +0100 | [diff] [blame] | 371 | psb_intel_clock(48000, &clock); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 372 | } |
| 373 | |
| 374 | /* XXX: It would be nice to validate the clocks, but we can't reuse |
| 375 | * i830PllIsValid() because it relies on the xf86_config connector |
| 376 | * configuration being accurate, which it isn't necessarily. |
| 377 | */ |
| 378 | |
| 379 | return clock.dot; |
| 380 | } |
| 381 | |
| 382 | /** Returns the currently programmed mode of the given pipe. */ |
| 383 | struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, |
| 384 | struct drm_crtc *crtc) |
| 385 | { |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 386 | struct gma_crtc *gma_crtc = to_gma_crtc(crtc); |
| 387 | int pipe = gma_crtc->pipe; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 388 | struct drm_display_mode *mode; |
| 389 | int htot; |
| 390 | int hsync; |
| 391 | int vtot; |
| 392 | int vsync; |
| 393 | struct drm_psb_private *dev_priv = dev->dev_private; |
Alan Cox | 6256304 | 2012-05-11 11:30:16 +0100 | [diff] [blame] | 394 | struct psb_pipe *p = &dev_priv->regs.pipe[pipe]; |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 395 | const struct psb_offset *map = &dev_priv->regmap[pipe]; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 396 | |
| 397 | if (gma_power_begin(dev, false)) { |
Alan Cox | 213a843 | 2012-05-11 11:31:22 +0100 | [diff] [blame] | 398 | htot = REG_READ(map->htotal); |
| 399 | hsync = REG_READ(map->hsync); |
| 400 | vtot = REG_READ(map->vtotal); |
| 401 | vsync = REG_READ(map->vsync); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 402 | gma_power_end(dev); |
| 403 | } else { |
Alan Cox | 6256304 | 2012-05-11 11:30:16 +0100 | [diff] [blame] | 404 | htot = p->htotal; |
| 405 | hsync = p->hsync; |
| 406 | vtot = p->vtotal; |
| 407 | vsync = p->vsync; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 408 | } |
| 409 | |
| 410 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); |
| 411 | if (!mode) |
| 412 | return NULL; |
| 413 | |
| 414 | mode->clock = psb_intel_crtc_clock_get(dev, crtc); |
| 415 | mode->hdisplay = (htot & 0xffff) + 1; |
| 416 | mode->htotal = ((htot & 0xffff0000) >> 16) + 1; |
| 417 | mode->hsync_start = (hsync & 0xffff) + 1; |
| 418 | mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; |
| 419 | mode->vdisplay = (vtot & 0xffff) + 1; |
| 420 | mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; |
| 421 | mode->vsync_start = (vsync & 0xffff) + 1; |
| 422 | mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; |
| 423 | |
| 424 | drm_mode_set_name(mode); |
| 425 | drm_mode_set_crtcinfo(mode, 0); |
| 426 | |
| 427 | return mode; |
| 428 | } |
| 429 | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 430 | const struct drm_crtc_helper_funcs psb_intel_helper_funcs = { |
Patrik Jakobsson | 42568dd | 2013-07-10 18:44:25 +0200 | [diff] [blame] | 431 | .dpms = gma_crtc_dpms, |
Patrik Jakobsson | 4855177 | 2013-07-10 17:40:54 +0200 | [diff] [blame] | 432 | .mode_fixup = gma_crtc_mode_fixup, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 433 | .mode_set = psb_intel_crtc_mode_set, |
Patrik Jakobsson | 00b1fe7 | 2013-07-10 18:37:03 +0200 | [diff] [blame] | 434 | .mode_set_base = gma_pipe_set_base, |
Patrik Jakobsson | 4855177 | 2013-07-10 17:40:54 +0200 | [diff] [blame] | 435 | .prepare = gma_crtc_prepare, |
| 436 | .commit = gma_crtc_commit, |
| 437 | .disable = gma_crtc_disable, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 438 | }; |
| 439 | |
| 440 | const struct drm_crtc_funcs psb_intel_crtc_funcs = { |
Patrik Jakobsson | 0e5b26a | 2013-07-12 15:32:18 +0200 | [diff] [blame] | 441 | .save = gma_crtc_save, |
| 442 | .restore = gma_crtc_restore, |
Patrik Jakobsson | 561573b | 2013-07-10 23:48:13 +0200 | [diff] [blame] | 443 | .cursor_set = gma_crtc_cursor_set, |
| 444 | .cursor_move = gma_crtc_cursor_move, |
Patrik Jakobsson | 6443ea1 | 2013-07-10 18:39:58 +0200 | [diff] [blame] | 445 | .gamma_set = gma_crtc_gamma_set, |
Patrik Jakobsson | 43a8302 | 2013-07-12 15:41:36 +0200 | [diff] [blame] | 446 | .set_config = gma_crtc_set_config, |
Patrik Jakobsson | b1255b8 | 2013-07-10 23:24:22 +0200 | [diff] [blame] | 447 | .destroy = gma_crtc_destroy, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 448 | }; |
| 449 | |
Patrik Jakobsson | 7f67c06 | 2013-07-02 17:07:59 +0200 | [diff] [blame] | 450 | const struct gma_clock_funcs psb_clock_funcs = { |
| 451 | .clock = psb_intel_clock, |
| 452 | .limit = psb_intel_limit, |
| 453 | .pll_is_valid = gma_pll_is_valid, |
| 454 | }; |
| 455 | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 456 | /* |
| 457 | * Set the default value of cursor control and base register |
| 458 | * to zero. This is a workaround for h/w defect on Oaktrail |
| 459 | */ |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 460 | static void psb_intel_cursor_init(struct drm_device *dev, |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 461 | struct gma_crtc *gma_crtc) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 462 | { |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 463 | struct drm_psb_private *dev_priv = dev->dev_private; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 464 | u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR }; |
| 465 | u32 base[3] = { CURABASE, CURBBASE, CURCBASE }; |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 466 | struct gtt_range *cursor_gt; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 467 | |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 468 | if (dev_priv->ops->cursor_needs_phys) { |
| 469 | /* Allocate 4 pages of stolen mem for a hardware cursor. That |
| 470 | * is enough for the 64 x 64 ARGB cursors we support. |
| 471 | */ |
Patrik Jakobsson | c269c68 | 2014-01-06 02:39:10 +0100 | [diff] [blame] | 472 | cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1, |
| 473 | PAGE_SIZE); |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 474 | if (!cursor_gt) { |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 475 | gma_crtc->cursor_gt = NULL; |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 476 | goto out; |
| 477 | } |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 478 | gma_crtc->cursor_gt = cursor_gt; |
| 479 | gma_crtc->cursor_addr = dev_priv->stolen_base + |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 480 | cursor_gt->offset; |
| 481 | } else { |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 482 | gma_crtc->cursor_gt = NULL; |
Patrik Jakobsson | bc79482 | 2012-05-21 15:27:30 +0100 | [diff] [blame] | 483 | } |
| 484 | |
| 485 | out: |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 486 | REG_WRITE(control[gma_crtc->pipe], 0); |
| 487 | REG_WRITE(base[gma_crtc->pipe], 0); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 488 | } |
| 489 | |
| 490 | void psb_intel_crtc_init(struct drm_device *dev, int pipe, |
| 491 | struct psb_intel_mode_device *mode_dev) |
| 492 | { |
| 493 | struct drm_psb_private *dev_priv = dev->dev_private; |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 494 | struct gma_crtc *gma_crtc; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 495 | int i; |
| 496 | uint16_t *r_base, *g_base, *b_base; |
| 497 | |
| 498 | /* We allocate a extra array of drm_connector pointers |
| 499 | * for fbdev after the crtc */ |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 500 | gma_crtc = kzalloc(sizeof(struct gma_crtc) + |
| 501 | (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), |
| 502 | GFP_KERNEL); |
| 503 | if (gma_crtc == NULL) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 504 | return; |
| 505 | |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 506 | gma_crtc->crtc_state = |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 507 | kzalloc(sizeof(struct psb_intel_crtc_state), GFP_KERNEL); |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 508 | if (!gma_crtc->crtc_state) { |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 509 | dev_err(dev->dev, "Crtc state error: No memory\n"); |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 510 | kfree(gma_crtc); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 511 | return; |
| 512 | } |
| 513 | |
| 514 | /* Set the CRTC operations from the chip specific data */ |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 515 | drm_crtc_init(dev, &gma_crtc->base, dev_priv->ops->crtc_funcs); |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 516 | |
Patrik Jakobsson | 5ea75e0 | 2013-06-30 21:39:00 +0200 | [diff] [blame] | 517 | /* Set the CRTC clock functions from chip specific data */ |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 518 | gma_crtc->clock_funcs = dev_priv->ops->clock_funcs; |
Patrik Jakobsson | 5ea75e0 | 2013-06-30 21:39:00 +0200 | [diff] [blame] | 519 | |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 520 | drm_mode_crtc_set_gamma_size(&gma_crtc->base, 256); |
| 521 | gma_crtc->pipe = pipe; |
| 522 | gma_crtc->plane = pipe; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 523 | |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 524 | r_base = gma_crtc->base.gamma_store; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 525 | g_base = r_base + 256; |
| 526 | b_base = g_base + 256; |
| 527 | for (i = 0; i < 256; i++) { |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 528 | gma_crtc->lut_r[i] = i; |
| 529 | gma_crtc->lut_g[i] = i; |
| 530 | gma_crtc->lut_b[i] = i; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 531 | r_base[i] = i << 8; |
| 532 | g_base[i] = i << 8; |
| 533 | b_base[i] = i << 8; |
| 534 | |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 535 | gma_crtc->lut_adj[i] = 0; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 536 | } |
| 537 | |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 538 | gma_crtc->mode_dev = mode_dev; |
| 539 | gma_crtc->cursor_addr = 0; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 540 | |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 541 | drm_crtc_helper_add(&gma_crtc->base, |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 542 | dev_priv->ops->crtc_helper); |
| 543 | |
| 544 | /* Setup the array of drm_connector pointer array */ |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 545 | gma_crtc->mode_set.crtc = &gma_crtc->base; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 546 | BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 547 | dev_priv->plane_to_crtc_mapping[gma_crtc->plane] != NULL); |
| 548 | dev_priv->plane_to_crtc_mapping[gma_crtc->plane] = &gma_crtc->base; |
| 549 | dev_priv->pipe_to_crtc_mapping[gma_crtc->pipe] = &gma_crtc->base; |
| 550 | gma_crtc->mode_set.connectors = (struct drm_connector **)(gma_crtc + 1); |
| 551 | gma_crtc->mode_set.num_connectors = 0; |
| 552 | psb_intel_cursor_init(dev, gma_crtc); |
Forest Bond | 4a68a74 | 2012-08-13 16:31:24 +0000 | [diff] [blame] | 553 | |
| 554 | /* Set to true so that the pipe is forced off on initial config. */ |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 555 | gma_crtc->active = true; |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 556 | } |
| 557 | |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 558 | struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) |
| 559 | { |
| 560 | struct drm_crtc *crtc = NULL; |
| 561 | |
| 562 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
Patrik Jakobsson | 6306865 | 2013-07-22 01:31:23 +0200 | [diff] [blame] | 563 | struct gma_crtc *gma_crtc = to_gma_crtc(crtc); |
| 564 | if (gma_crtc->pipe == pipe) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 565 | break; |
| 566 | } |
| 567 | return crtc; |
| 568 | } |
| 569 | |
Patrik Jakobsson | a3d5d75 | 2013-07-22 17:05:25 +0200 | [diff] [blame] | 570 | int gma_connector_clones(struct drm_device *dev, int type_mask) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 571 | { |
| 572 | int index_mask = 0; |
| 573 | struct drm_connector *connector; |
| 574 | int entry = 0; |
| 575 | |
| 576 | list_for_each_entry(connector, &dev->mode_config.connector_list, |
| 577 | head) { |
Patrik Jakobsson | 367e440 | 2013-07-22 17:45:26 +0200 | [diff] [blame] | 578 | struct gma_encoder *gma_encoder = gma_attached_encoder(connector); |
| 579 | if (type_mask & (1 << gma_encoder->type)) |
Alan Cox | 89c7813 | 2011-11-03 18:22:15 +0000 | [diff] [blame] | 580 | index_mask |= (1 << entry); |
| 581 | entry++; |
| 582 | } |
| 583 | return index_mask; |
| 584 | } |