2 * Copyright (C) 2009 Francisco Jerez.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include "nouveau_drv.h"
29 #include "nouveau_encoder.h"
30 #include "nouveau_connector.h"
31 #include "nouveau_crtc.h"
32 #include "nouveau_hw.h"
33 #include "drm_crtc_helper.h"
35 #include "i2c/ch7006.h"
38 struct i2c_board_info board_info
;
39 struct drm_encoder_funcs funcs
;
40 struct drm_encoder_helper_funcs hfuncs
;
43 } nv04_tv_encoder_info
[] = {
45 .board_info
= { I2C_BOARD_INFO("ch7006", 0x75) },
46 .params
= &(struct ch7006_encoder_params
) {
47 CH7006_FORMAT_RGB24m12I
, CH7006_CLOCK_MASTER
,
49 CH7006_SYNC_SLAVE
, CH7006_SYNC_SEPARATED
,
50 CH7006_POUT_3_3V
, CH7006_ACTIVE_HSYNC
55 static bool probe_i2c_addr(struct i2c_adapter
*adapter
, int addr
)
57 struct i2c_msg msg
= {
62 return i2c_transfer(adapter
, &msg
, 1) == 1;
65 int nv04_tv_identify(struct drm_device
*dev
, int i2c_index
)
67 struct nouveau_i2c_chan
*i2c
;
71 NV_TRACE(dev
, "Probing TV encoders on I2C bus: %d\n", i2c_index
);
73 i2c
= nouveau_i2c_find(dev
, i2c_index
);
77 was_locked
= NVLockVgaCrtcs(dev
, false);
79 for (i
= 0; i
< ARRAY_SIZE(nv04_tv_encoder_info
); i
++) {
80 if (probe_i2c_addr(&i2c
->adapter
,
81 nv04_tv_encoder_info
[i
].board_info
.addr
)) {
87 if (i
< ARRAY_SIZE(nv04_tv_encoder_info
)) {
88 NV_TRACE(dev
, "Detected TV encoder: %s\n",
89 nv04_tv_encoder_info
[i
].board_info
.type
);
92 NV_TRACE(dev
, "No TV encoders found.\n");
96 NVLockVgaCrtcs(dev
, was_locked
);
100 #define PLLSEL_TV_CRTC1_MASK \
101 (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \
102 | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1)
103 #define PLLSEL_TV_CRTC2_MASK \
104 (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK2 \
105 | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK2)
107 static void nv04_tv_dpms(struct drm_encoder
*encoder
, int mode
)
109 struct drm_device
*dev
= encoder
->dev
;
110 struct nouveau_encoder
*nv_encoder
= nouveau_encoder(encoder
);
111 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
112 struct nv04_mode_state
*state
= &dev_priv
->mode_reg
;
115 NV_INFO(dev
, "Setting dpms mode %d on TV encoder (output %d)\n",
116 mode
, nv_encoder
->dcb
->index
);
118 state
->pllsel
&= ~(PLLSEL_TV_CRTC1_MASK
| PLLSEL_TV_CRTC2_MASK
);
120 if (mode
== DRM_MODE_DPMS_ON
) {
121 int head
= nouveau_crtc(encoder
->crtc
)->index
;
122 crtc1A
= NVReadVgaCrtc(dev
, head
, NV_CIO_CRE_RPC1_INDEX
);
124 state
->pllsel
|= head
? PLLSEL_TV_CRTC2_MASK
:
125 PLLSEL_TV_CRTC1_MASK
;
130 NVWriteVgaCrtc(dev
, head
, NV_CIO_CRE_RPC1_INDEX
, crtc1A
);
133 NVWriteRAMDAC(dev
, 0, NV_PRAMDAC_PLL_COEFF_SELECT
, state
->pllsel
);
135 to_encoder_slave(encoder
)->slave_funcs
->dpms(encoder
, mode
);
138 static void nv04_tv_bind(struct drm_device
*dev
, int head
, bool bind
)
140 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
141 struct nv04_crtc_reg
*state
= &dev_priv
->mode_reg
.crtc_reg
[head
];
146 state
->CRTC
[NV_CIO_CRE_LCD__INDEX
] = 0;
147 state
->CRTC
[NV_CIO_CRE_49
] |= 0x10;
149 state
->CRTC
[NV_CIO_CRE_49
] &= ~0x10;
152 NVWriteVgaCrtc(dev
, head
, NV_CIO_CRE_LCD__INDEX
,
153 state
->CRTC
[NV_CIO_CRE_LCD__INDEX
]);
154 NVWriteVgaCrtc(dev
, head
, NV_CIO_CRE_49
,
155 state
->CRTC
[NV_CIO_CRE_49
]);
156 NVWriteRAMDAC(dev
, head
, NV_PRAMDAC_TV_SETUP
,
160 static void nv04_tv_prepare(struct drm_encoder
*encoder
)
162 struct drm_device
*dev
= encoder
->dev
;
163 int head
= nouveau_crtc(encoder
->crtc
)->index
;
164 struct drm_encoder_helper_funcs
*helper
= encoder
->helper_private
;
166 helper
->dpms(encoder
, DRM_MODE_DPMS_OFF
);
168 nv04_dfp_disable(dev
, head
);
170 if (nv_two_heads(dev
))
171 nv04_tv_bind(dev
, head
^ 1, false);
173 nv04_tv_bind(dev
, head
, true);
176 static void nv04_tv_mode_set(struct drm_encoder
*encoder
,
177 struct drm_display_mode
*mode
,
178 struct drm_display_mode
*adjusted_mode
)
180 struct drm_device
*dev
= encoder
->dev
;
181 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
182 struct nouveau_crtc
*nv_crtc
= nouveau_crtc(encoder
->crtc
);
183 struct nv04_crtc_reg
*regp
= &dev_priv
->mode_reg
.crtc_reg
[nv_crtc
->index
];
185 regp
->tv_htotal
= adjusted_mode
->htotal
;
186 regp
->tv_vtotal
= adjusted_mode
->vtotal
;
188 /* These delay the TV signals with respect to the VGA port,
189 * they might be useful if we ever allow a CRTC to drive
193 regp
->tv_hsync_delay
= 1;
194 regp
->tv_hsync_delay2
= 64;
196 regp
->tv_vsync_delay
= 1;
198 to_encoder_slave(encoder
)->slave_funcs
->mode_set(encoder
, mode
, adjusted_mode
);
201 static void nv04_tv_commit(struct drm_encoder
*encoder
)
203 struct nouveau_encoder
*nv_encoder
= nouveau_encoder(encoder
);
204 struct drm_device
*dev
= encoder
->dev
;
205 struct nouveau_crtc
*nv_crtc
= nouveau_crtc(encoder
->crtc
);
206 struct drm_encoder_helper_funcs
*helper
= encoder
->helper_private
;
208 helper
->dpms(encoder
, DRM_MODE_DPMS_ON
);
210 NV_INFO(dev
, "Output %s is running on CRTC %d using output %c\n",
211 drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder
)->base
), nv_crtc
->index
,
212 '@' + ffs(nv_encoder
->dcb
->or));
215 static void nv04_tv_destroy(struct drm_encoder
*encoder
)
217 struct nouveau_encoder
*nv_encoder
= nouveau_encoder(encoder
);
219 to_encoder_slave(encoder
)->slave_funcs
->destroy(encoder
);
221 drm_encoder_cleanup(encoder
);
226 int nv04_tv_create(struct drm_device
*dev
, struct dcb_entry
*entry
)
228 struct nouveau_encoder
*nv_encoder
;
229 struct drm_encoder
*encoder
;
230 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
231 struct i2c_adapter
*adap
;
232 struct drm_encoder_funcs
*funcs
= NULL
;
233 struct drm_encoder_helper_funcs
*hfuncs
= NULL
;
234 struct drm_encoder_slave_funcs
*sfuncs
= NULL
;
235 int i2c_index
= entry
->i2c_index
;
239 /* Ensure that we can talk to this encoder */
240 type
= nv04_tv_identify(dev
, i2c_index
);
244 /* Allocate the necessary memory */
245 nv_encoder
= kzalloc(sizeof(*nv_encoder
), GFP_KERNEL
);
249 /* Initialize the common members */
250 encoder
= to_drm_encoder(nv_encoder
);
252 funcs
= &nv04_tv_encoder_info
[type
].funcs
;
253 hfuncs
= &nv04_tv_encoder_info
[type
].hfuncs
;
255 drm_encoder_init(dev
, encoder
, funcs
, DRM_MODE_ENCODER_TVDAC
);
256 drm_encoder_helper_add(encoder
, hfuncs
);
258 encoder
->possible_crtcs
= entry
->heads
;
259 encoder
->possible_clones
= 0;
261 nv_encoder
->dcb
= entry
;
262 nv_encoder
->or = ffs(entry
->or) - 1;
264 /* Run the slave-specific initialization */
265 adap
= &dev_priv
->vbios
.dcb
.i2c
[i2c_index
].chan
->adapter
;
267 was_locked
= NVLockVgaCrtcs(dev
, false);
269 ret
= drm_i2c_encoder_init(encoder
->dev
, to_encoder_slave(encoder
), adap
,
270 &nv04_tv_encoder_info
[type
].board_info
);
272 NVLockVgaCrtcs(dev
, was_locked
);
277 /* Fill the function pointers */
278 sfuncs
= to_encoder_slave(encoder
)->slave_funcs
;
280 *funcs
= (struct drm_encoder_funcs
) {
281 .destroy
= nv04_tv_destroy
,
284 *hfuncs
= (struct drm_encoder_helper_funcs
) {
285 .dpms
= nv04_tv_dpms
,
286 .save
= sfuncs
->save
,
287 .restore
= sfuncs
->restore
,
288 .mode_fixup
= sfuncs
->mode_fixup
,
289 .prepare
= nv04_tv_prepare
,
290 .commit
= nv04_tv_commit
,
291 .mode_set
= nv04_tv_mode_set
,
292 .detect
= sfuncs
->detect
,
295 /* Set the slave encoder configuration */
296 sfuncs
->set_config(encoder
, nv04_tv_encoder_info
[type
].params
);
301 drm_encoder_cleanup(encoder
);