162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2009 Francisco Jerez. 362306a36Sopenharmony_ci * All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 662306a36Sopenharmony_ci * a copy of this software and associated documentation files (the 762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 962306a36Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to 1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1162306a36Sopenharmony_ci * the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1462306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial 1562306a36Sopenharmony_ci * portions of the Software. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1862306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1962306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 2062306a36Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 2162306a36Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 2262306a36Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2362306a36Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "ch7006_priv.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciconst char * const ch7006_tv_norm_names[] = { 3062306a36Sopenharmony_ci [TV_NORM_PAL] = "PAL", 3162306a36Sopenharmony_ci [TV_NORM_PAL_M] = "PAL-M", 3262306a36Sopenharmony_ci [TV_NORM_PAL_N] = "PAL-N", 3362306a36Sopenharmony_ci [TV_NORM_PAL_NC] = "PAL-Nc", 3462306a36Sopenharmony_ci [TV_NORM_PAL_60] = "PAL-60", 3562306a36Sopenharmony_ci [TV_NORM_NTSC_M] = "NTSC-M", 3662306a36Sopenharmony_ci [TV_NORM_NTSC_J] = "NTSC-J", 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define NTSC_LIKE_TIMINGS .vrefresh = 60 * fixed1/1.001, \ 4062306a36Sopenharmony_ci .vdisplay = 480, \ 4162306a36Sopenharmony_ci .vtotal = 525, \ 4262306a36Sopenharmony_ci .hvirtual = 660 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define PAL_LIKE_TIMINGS .vrefresh = 50 * fixed1, \ 4562306a36Sopenharmony_ci .vdisplay = 576, \ 4662306a36Sopenharmony_ci .vtotal = 625, \ 4762306a36Sopenharmony_ci .hvirtual = 810 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciconst struct ch7006_tv_norm_info ch7006_tv_norms[] = { 5062306a36Sopenharmony_ci [TV_NORM_NTSC_M] = { 5162306a36Sopenharmony_ci NTSC_LIKE_TIMINGS, 5262306a36Sopenharmony_ci .black_level = 0.339 * fixed1, 5362306a36Sopenharmony_ci .subc_freq = 3579545 * fixed1, 5462306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC), 5562306a36Sopenharmony_ci .voffset = 0, 5662306a36Sopenharmony_ci }, 5762306a36Sopenharmony_ci [TV_NORM_NTSC_J] = { 5862306a36Sopenharmony_ci NTSC_LIKE_TIMINGS, 5962306a36Sopenharmony_ci .black_level = 0.286 * fixed1, 6062306a36Sopenharmony_ci .subc_freq = 3579545 * fixed1, 6162306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC_J), 6262306a36Sopenharmony_ci .voffset = 0, 6362306a36Sopenharmony_ci }, 6462306a36Sopenharmony_ci [TV_NORM_PAL] = { 6562306a36Sopenharmony_ci PAL_LIKE_TIMINGS, 6662306a36Sopenharmony_ci .black_level = 0.3 * fixed1, 6762306a36Sopenharmony_ci .subc_freq = 4433618.75 * fixed1, 6862306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), 6962306a36Sopenharmony_ci .voffset = 0, 7062306a36Sopenharmony_ci }, 7162306a36Sopenharmony_ci [TV_NORM_PAL_M] = { 7262306a36Sopenharmony_ci NTSC_LIKE_TIMINGS, 7362306a36Sopenharmony_ci .black_level = 0.339 * fixed1, 7462306a36Sopenharmony_ci .subc_freq = 3575611.433 * fixed1, 7562306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), 7662306a36Sopenharmony_ci .voffset = 16, 7762306a36Sopenharmony_ci }, 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* The following modes seem to work right but they're 8062306a36Sopenharmony_ci * undocumented */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci [TV_NORM_PAL_N] = { 8362306a36Sopenharmony_ci PAL_LIKE_TIMINGS, 8462306a36Sopenharmony_ci .black_level = 0.339 * fixed1, 8562306a36Sopenharmony_ci .subc_freq = 4433618.75 * fixed1, 8662306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), 8762306a36Sopenharmony_ci .voffset = 0, 8862306a36Sopenharmony_ci }, 8962306a36Sopenharmony_ci [TV_NORM_PAL_NC] = { 9062306a36Sopenharmony_ci PAL_LIKE_TIMINGS, 9162306a36Sopenharmony_ci .black_level = 0.3 * fixed1, 9262306a36Sopenharmony_ci .subc_freq = 3582056.25 * fixed1, 9362306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), 9462306a36Sopenharmony_ci .voffset = 0, 9562306a36Sopenharmony_ci }, 9662306a36Sopenharmony_ci [TV_NORM_PAL_60] = { 9762306a36Sopenharmony_ci NTSC_LIKE_TIMINGS, 9862306a36Sopenharmony_ci .black_level = 0.3 * fixed1, 9962306a36Sopenharmony_ci .subc_freq = 4433618.75 * fixed1, 10062306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), 10162306a36Sopenharmony_ci .voffset = 16, 10262306a36Sopenharmony_ci }, 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define __MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ 10662306a36Sopenharmony_ci subc, scale, scale_mask, norm_mask, e_hd, e_vd) { \ 10762306a36Sopenharmony_ci .mode = { \ 10862306a36Sopenharmony_ci .name = #hd "x" #vd, \ 10962306a36Sopenharmony_ci .status = 0, \ 11062306a36Sopenharmony_ci .type = DRM_MODE_TYPE_DRIVER, \ 11162306a36Sopenharmony_ci .clock = f, \ 11262306a36Sopenharmony_ci .hdisplay = hd, \ 11362306a36Sopenharmony_ci .hsync_start = e_hd + 16, \ 11462306a36Sopenharmony_ci .hsync_end = e_hd + 80, \ 11562306a36Sopenharmony_ci .htotal = ht, \ 11662306a36Sopenharmony_ci .hskew = 0, \ 11762306a36Sopenharmony_ci .vdisplay = vd, \ 11862306a36Sopenharmony_ci .vsync_start = vd + 10, \ 11962306a36Sopenharmony_ci .vsync_end = vd + 26, \ 12062306a36Sopenharmony_ci .vtotal = vt, \ 12162306a36Sopenharmony_ci .vscan = 0, \ 12262306a36Sopenharmony_ci .flags = DRM_MODE_FLAG_##hsynp##HSYNC | \ 12362306a36Sopenharmony_ci DRM_MODE_FLAG_##vsynp##VSYNC, \ 12462306a36Sopenharmony_ci }, \ 12562306a36Sopenharmony_ci .enc_hdisp = e_hd, \ 12662306a36Sopenharmony_ci .enc_vdisp = e_vd, \ 12762306a36Sopenharmony_ci .subc_coeff = subc * fixed1, \ 12862306a36Sopenharmony_ci .dispmode = bitfs(CH7006_DISPMODE_SCALING_RATIO, scale) | \ 12962306a36Sopenharmony_ci bitfs(CH7006_DISPMODE_INPUT_RES, e_hd##x##e_vd), \ 13062306a36Sopenharmony_ci .valid_scales = scale_mask, \ 13162306a36Sopenharmony_ci .valid_norms = norm_mask \ 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#define MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ 13562306a36Sopenharmony_ci subc, scale, scale_mask, norm_mask) \ 13662306a36Sopenharmony_ci __MODE(f, hd, vd, ht, vt, hsynp, vsynp, subc, scale, \ 13762306a36Sopenharmony_ci scale_mask, norm_mask, hd, vd) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define NTSC_LIKE (1 << TV_NORM_NTSC_M | 1 << TV_NORM_NTSC_J | \ 14062306a36Sopenharmony_ci 1 << TV_NORM_PAL_M | 1 << TV_NORM_PAL_60) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC) 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciconst struct ch7006_mode ch7006_modes[] = { 14562306a36Sopenharmony_ci MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE), 14662306a36Sopenharmony_ci MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE), 14762306a36Sopenharmony_ci MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE), 14862306a36Sopenharmony_ci MODE(24671, 512, 384, 784, 525, N, N, 174.0874153, 1_1, 0x3, NTSC_LIKE), 14962306a36Sopenharmony_ci MODE(28125, 720, 400, 1125, 500, N, N, 135.742176298, 5_4, 0x6, PAL_LIKE), 15062306a36Sopenharmony_ci MODE(34875, 720, 400, 1116, 625, N, N, 109.469496898, 1_1, 0x1, PAL_LIKE), 15162306a36Sopenharmony_ci MODE(23790, 720, 400, 945, 420, N, N, 160.475642016, 5_4, 0x4, NTSC_LIKE), 15262306a36Sopenharmony_ci MODE(29455, 720, 400, 936, 525, N, N, 129.614941843, 1_1, 0x3, NTSC_LIKE), 15362306a36Sopenharmony_ci MODE(25000, 640, 400, 1000, 500, N, N, 152.709948279, 5_4, 0x6, PAL_LIKE), 15462306a36Sopenharmony_ci MODE(31500, 640, 400, 1008, 625, N, N, 121.198371646, 1_1, 0x1, PAL_LIKE), 15562306a36Sopenharmony_ci MODE(21147, 640, 400, 840, 420, N, N, 180.535097338, 5_4, 0x4, NTSC_LIKE), 15662306a36Sopenharmony_ci MODE(26434, 640, 400, 840, 525, N, N, 144.42807787, 1_1, 0x2, NTSC_LIKE), 15762306a36Sopenharmony_ci MODE(30210, 640, 400, 840, 600, N, N, 126.374568276, 7_8, 0x1, NTSC_LIKE), 15862306a36Sopenharmony_ci MODE(21000, 640, 480, 840, 500, N, N, 181.797557582, 5_4, 0x4, PAL_LIKE), 15962306a36Sopenharmony_ci MODE(26250, 640, 480, 840, 625, N, N, 145.438046066, 1_1, 0x2, PAL_LIKE), 16062306a36Sopenharmony_ci MODE(31500, 640, 480, 840, 750, N, N, 121.198371646, 5_6, 0x1, PAL_LIKE), 16162306a36Sopenharmony_ci MODE(24671, 640, 480, 784, 525, N, N, 174.0874153, 1_1, 0x4, NTSC_LIKE), 16262306a36Sopenharmony_ci MODE(28196, 640, 480, 784, 600, N, N, 152.326488422, 7_8, 0x2, NTSC_LIKE), 16362306a36Sopenharmony_ci MODE(30210, 640, 480, 800, 630, N, N, 142.171389101, 5_6, 0x1, NTSC_LIKE), 16462306a36Sopenharmony_ci __MODE(29500, 720, 576, 944, 625, P, P, 145.592111636, 1_1, 0x7, PAL_LIKE, 800, 600), 16562306a36Sopenharmony_ci MODE(36000, 800, 600, 960, 750, P, P, 119.304647022, 5_6, 0x6, PAL_LIKE), 16662306a36Sopenharmony_ci MODE(39000, 800, 600, 936, 836, P, P, 110.127366499, 3_4, 0x1, PAL_LIKE), 16762306a36Sopenharmony_ci MODE(39273, 800, 600, 1040, 630, P, P, 145.816809399, 5_6, 0x4, NTSC_LIKE), 16862306a36Sopenharmony_ci MODE(43636, 800, 600, 1040, 700, P, P, 131.235128487, 3_4, 0x2, NTSC_LIKE), 16962306a36Sopenharmony_ci MODE(47832, 800, 600, 1064, 750, P, P, 119.723275165, 7_10, 0x1, NTSC_LIKE), 17062306a36Sopenharmony_ci {} 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciconst struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, 17462306a36Sopenharmony_ci const struct drm_display_mode *drm_mode) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct ch7006_priv *priv = to_ch7006_priv(encoder); 17762306a36Sopenharmony_ci const struct ch7006_mode *mode; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci for (mode = ch7006_modes; mode->mode.clock; mode++) { 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (~mode->valid_norms & 1<<priv->norm) 18262306a36Sopenharmony_ci continue; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (mode->mode.hdisplay != drm_mode->hdisplay || 18562306a36Sopenharmony_ci mode->mode.vdisplay != drm_mode->vdisplay || 18662306a36Sopenharmony_ci mode->mode.vtotal != drm_mode->vtotal || 18762306a36Sopenharmony_ci mode->mode.htotal != drm_mode->htotal || 18862306a36Sopenharmony_ci mode->mode.clock != drm_mode->clock) 18962306a36Sopenharmony_ci continue; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return mode; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return NULL; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* Some common HW state calculation code */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid ch7006_setup_levels(struct drm_encoder *encoder) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 20262306a36Sopenharmony_ci struct ch7006_priv *priv = to_ch7006_priv(encoder); 20362306a36Sopenharmony_ci uint8_t *regs = priv->state.regs; 20462306a36Sopenharmony_ci const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; 20562306a36Sopenharmony_ci int gain; 20662306a36Sopenharmony_ci int black_level; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Set DAC_GAIN if the voltage drop between white and black is 20962306a36Sopenharmony_ci * high enough. */ 21062306a36Sopenharmony_ci if (norm->black_level < 339*fixed1/1000) { 21162306a36Sopenharmony_ci gain = 76; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci regs[CH7006_INPUT_FORMAT] |= CH7006_INPUT_FORMAT_DAC_GAIN; 21462306a36Sopenharmony_ci } else { 21562306a36Sopenharmony_ci gain = 71; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci regs[CH7006_INPUT_FORMAT] &= ~CH7006_INPUT_FORMAT_DAC_GAIN; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci black_level = round_fixed(norm->black_level*26625)/gain; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Correct it with the specified brightness. */ 22362306a36Sopenharmony_ci black_level = interpolate(90, black_level, 208, priv->brightness); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci regs[CH7006_BLACK_LEVEL] = bitf(CH7006_BLACK_LEVEL_0, black_level); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ch7006_dbg(client, "black level: %d\n", black_level); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_civoid ch7006_setup_subcarrier(struct drm_encoder *encoder) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 23362306a36Sopenharmony_ci struct ch7006_priv *priv = to_ch7006_priv(encoder); 23462306a36Sopenharmony_ci struct ch7006_state *state = &priv->state; 23562306a36Sopenharmony_ci const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; 23662306a36Sopenharmony_ci const struct ch7006_mode *mode = priv->mode; 23762306a36Sopenharmony_ci uint32_t subc_inc; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci subc_inc = round_fixed((mode->subc_coeff >> 8) 24062306a36Sopenharmony_ci * (norm->subc_freq >> 24)); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC0, 28, subc_inc); 24362306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC1, 24, subc_inc); 24462306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC2, 20, subc_inc); 24562306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC3, 16, subc_inc); 24662306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC4, 12, subc_inc); 24762306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC5, 8, subc_inc); 24862306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC6, 4, subc_inc); 24962306a36Sopenharmony_ci setbitf(state, CH7006_SUBC_INC7, 0, subc_inc); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ch7006_dbg(client, "subcarrier inc: %u\n", subc_inc); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_civoid ch7006_setup_pll(struct drm_encoder *encoder) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 25762306a36Sopenharmony_ci struct ch7006_priv *priv = to_ch7006_priv(encoder); 25862306a36Sopenharmony_ci uint8_t *regs = priv->state.regs; 25962306a36Sopenharmony_ci const struct ch7006_mode *mode = priv->mode; 26062306a36Sopenharmony_ci int n, best_n = 0; 26162306a36Sopenharmony_ci int m, best_m = 0; 26262306a36Sopenharmony_ci int freq, best_freq = 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci for (n = 0; n < CH7006_MAXN; n++) { 26562306a36Sopenharmony_ci for (m = 0; m < CH7006_MAXM; m++) { 26662306a36Sopenharmony_ci freq = CH7006_FREQ0*(n+2)/(m+2); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (abs(freq - mode->mode.clock) < 26962306a36Sopenharmony_ci abs(best_freq - mode->mode.clock)) { 27062306a36Sopenharmony_ci best_freq = freq; 27162306a36Sopenharmony_ci best_n = n; 27262306a36Sopenharmony_ci best_m = m; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci regs[CH7006_PLLOV] = bitf(CH7006_PLLOV_N_8, best_n) | 27862306a36Sopenharmony_ci bitf(CH7006_PLLOV_M_8, best_m); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci regs[CH7006_PLLM] = bitf(CH7006_PLLM_0, best_m); 28162306a36Sopenharmony_ci regs[CH7006_PLLN] = bitf(CH7006_PLLN_0, best_n); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (best_n < 108) 28462306a36Sopenharmony_ci regs[CH7006_PLL_CONTROL] |= CH7006_PLL_CONTROL_CAPACITOR; 28562306a36Sopenharmony_ci else 28662306a36Sopenharmony_ci regs[CH7006_PLL_CONTROL] &= ~CH7006_PLL_CONTROL_CAPACITOR; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ch7006_dbg(client, "n=%d m=%d f=%d c=%d\n", 28962306a36Sopenharmony_ci best_n, best_m, best_freq, best_n < 108); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_civoid ch7006_setup_power_state(struct drm_encoder *encoder) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct ch7006_priv *priv = to_ch7006_priv(encoder); 29562306a36Sopenharmony_ci uint8_t *power = &priv->state.regs[CH7006_POWER]; 29662306a36Sopenharmony_ci int subconnector; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci subconnector = priv->select_subconnector ? priv->select_subconnector : 29962306a36Sopenharmony_ci priv->subconnector; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci *power = CH7006_POWER_RESET; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (priv->last_dpms == DRM_MODE_DPMS_ON) { 30462306a36Sopenharmony_ci switch (subconnector) { 30562306a36Sopenharmony_ci case DRM_MODE_SUBCONNECTOR_SVIDEO: 30662306a36Sopenharmony_ci *power |= bitfs(CH7006_POWER_LEVEL, CVBS_OFF); 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci case DRM_MODE_SUBCONNECTOR_Composite: 30962306a36Sopenharmony_ci *power |= bitfs(CH7006_POWER_LEVEL, SVIDEO_OFF); 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci case DRM_MODE_SUBCONNECTOR_SCART: 31262306a36Sopenharmony_ci *power |= bitfs(CH7006_POWER_LEVEL, NORMAL) | 31362306a36Sopenharmony_ci CH7006_POWER_SCART; 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci if (priv->chip_version >= 0x20) 31962306a36Sopenharmony_ci *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); 32062306a36Sopenharmony_ci else 32162306a36Sopenharmony_ci *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_civoid ch7006_setup_properties(struct drm_encoder *encoder) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 32862306a36Sopenharmony_ci struct ch7006_priv *priv = to_ch7006_priv(encoder); 32962306a36Sopenharmony_ci struct ch7006_state *state = &priv->state; 33062306a36Sopenharmony_ci const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; 33162306a36Sopenharmony_ci const struct ch7006_mode *ch_mode = priv->mode; 33262306a36Sopenharmony_ci const struct drm_display_mode *mode = &ch_mode->mode; 33362306a36Sopenharmony_ci uint8_t *regs = state->regs; 33462306a36Sopenharmony_ci int flicker, contrast, hpos, vpos; 33562306a36Sopenharmony_ci uint64_t scale, aspect; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci flicker = interpolate(0, 2, 3, priv->flicker); 33862306a36Sopenharmony_ci regs[CH7006_FFILTER] = bitf(CH7006_FFILTER_TEXT, flicker) | 33962306a36Sopenharmony_ci bitf(CH7006_FFILTER_LUMA, flicker) | 34062306a36Sopenharmony_ci bitf(CH7006_FFILTER_CHROMA, 1); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci contrast = interpolate(0, 5, 7, priv->contrast); 34362306a36Sopenharmony_ci regs[CH7006_CONTRAST] = bitf(CH7006_CONTRAST_0, contrast); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci scale = norm->vtotal*fixed1; 34662306a36Sopenharmony_ci do_div(scale, mode->vtotal); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci aspect = ch_mode->enc_hdisp*fixed1; 34962306a36Sopenharmony_ci do_div(aspect, ch_mode->enc_vdisp); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci hpos = round_fixed((norm->hvirtual * aspect - mode->hdisplay * scale) 35262306a36Sopenharmony_ci * priv->hmargin * mode->vtotal) / norm->vtotal / 100 / 4; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci setbitf(state, CH7006_POV, HPOS_8, hpos); 35562306a36Sopenharmony_ci setbitf(state, CH7006_HPOS, 0, hpos); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci vpos = max(0, norm->vdisplay - round_fixed(mode->vdisplay*scale) 35862306a36Sopenharmony_ci + norm->voffset) * priv->vmargin / 100 / 2; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci setbitf(state, CH7006_POV, VPOS_8, vpos); 36162306a36Sopenharmony_ci setbitf(state, CH7006_VPOS, 0, vpos); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci ch7006_dbg(client, "hpos: %d, vpos: %d\n", hpos, vpos); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/* HW access functions */ 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_civoid ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci uint8_t buf[] = {addr, val}; 37162306a36Sopenharmony_ci int ret; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); 37462306a36Sopenharmony_ci if (ret < 0) 37562306a36Sopenharmony_ci ch7006_err(client, "Error %d writing to subaddress 0x%x\n", 37662306a36Sopenharmony_ci ret, addr); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ciuint8_t ch7006_read(struct i2c_client *client, uint8_t addr) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci uint8_t val; 38262306a36Sopenharmony_ci int ret; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci ret = i2c_master_send(client, &addr, sizeof(addr)); 38562306a36Sopenharmony_ci if (ret < 0) 38662306a36Sopenharmony_ci goto fail; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci ret = i2c_master_recv(client, &val, sizeof(val)); 38962306a36Sopenharmony_ci if (ret < 0) 39062306a36Sopenharmony_ci goto fail; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return val; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cifail: 39562306a36Sopenharmony_ci ch7006_err(client, "Error %d reading from subaddress 0x%x\n", 39662306a36Sopenharmony_ci ret, addr); 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_civoid ch7006_state_load(struct i2c_client *client, 40162306a36Sopenharmony_ci struct ch7006_state *state) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_POWER); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_DISPMODE); 40662306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_FFILTER); 40762306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_BWIDTH); 40862306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_INPUT_FORMAT); 40962306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_CLKMODE); 41062306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_START_ACTIVE); 41162306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_POV); 41262306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); 41362306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_HPOS); 41462306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_VPOS); 41562306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_INPUT_SYNC); 41662306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_DETECT); 41762306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_CONTRAST); 41862306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_PLLOV); 41962306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_PLLM); 42062306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_PLLN); 42162306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_BCLKOUT); 42262306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC0); 42362306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC1); 42462306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC2); 42562306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC3); 42662306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC4); 42762306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC5); 42862306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC6); 42962306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_SUBC_INC7); 43062306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_PLL_CONTROL); 43162306a36Sopenharmony_ci ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_civoid ch7006_state_save(struct i2c_client *client, 43562306a36Sopenharmony_ci struct ch7006_state *state) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_POWER); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_DISPMODE); 44062306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_FFILTER); 44162306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_BWIDTH); 44262306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_INPUT_FORMAT); 44362306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_CLKMODE); 44462306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_START_ACTIVE); 44562306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_POV); 44662306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_BLACK_LEVEL); 44762306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_HPOS); 44862306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_VPOS); 44962306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_INPUT_SYNC); 45062306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_DETECT); 45162306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_CONTRAST); 45262306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_PLLOV); 45362306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_PLLM); 45462306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_PLLN); 45562306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_BCLKOUT); 45662306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC0); 45762306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC1); 45862306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC2); 45962306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC3); 46062306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC4); 46162306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC5); 46262306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC6); 46362306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_SUBC_INC7); 46462306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_PLL_CONTROL); 46562306a36Sopenharmony_ci ch7006_save_reg(client, state, CH7006_CALC_SUBC_INC0); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci state->regs[CH7006_FFILTER] = (state->regs[CH7006_FFILTER] & 0xf0) | 46862306a36Sopenharmony_ci (state->regs[CH7006_FFILTER] & 0x0c) >> 2 | 46962306a36Sopenharmony_ci (state->regs[CH7006_FFILTER] & 0x03) << 2; 47062306a36Sopenharmony_ci} 471