1 /* 2 * Copyright (C) 2016 BayLibre, SAS 3 * Author: Neil Armstrong <narmstrong@baylibre.com> 4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of the 9 * License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <drm/drmP.h> 23 #include "meson_drv.h" 24 #include "meson_vclk.h" 25 26 /* 27 * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL. 28 * We handle the following encodings : 29 * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks 30 * 31 * What is missing : 32 * - HDMI Pixel Clocks generation 33 */ 34 35 /* HHI Registers */ 36 #define HHI_VID_PLL_CLK_DIV 0x1a0 /* 0x68 offset in data sheet */ 37 #define VID_PLL_EN BIT(19) 38 #define VID_PLL_BYPASS BIT(18) 39 #define VID_PLL_PRESET BIT(15) 40 #define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */ 41 #define VCLK2_DIV_MASK 0xff 42 #define VCLK2_DIV_EN BIT(16) 43 #define VCLK2_DIV_RESET BIT(17) 44 #define CTS_VDAC_SEL_MASK (0xf << 28) 45 #define CTS_VDAC_SEL_SHIFT 28 46 #define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */ 47 #define VCLK2_EN BIT(19) 48 #define VCLK2_SEL_MASK (0x7 << 16) 49 #define VCLK2_SEL_SHIFT 16 50 #define VCLK2_SOFT_RESET BIT(15) 51 #define VCLK2_DIV1_EN BIT(0) 52 #define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ 53 #define CTS_ENCI_SEL_MASK (0xf << 28) 54 #define CTS_ENCI_SEL_SHIFT 28 55 #define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ 56 #define CTS_ENCI_EN BIT(0) 57 #define CTS_VDAC_EN BIT(4) 58 59 #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ 60 #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ 61 62 #define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ 63 #define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ 64 #define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ 65 #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ 66 #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ 67 #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ 68 69 #define HDMI_PLL_RESET BIT(28) 70 #define HDMI_PLL_LOCK BIT(31) 71 72 /* 73 * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC 74 * 75 * TOFIX: Refactor into table to also handle HDMI frequency and paths 76 */ 77 static void meson_venci_cvbs_clock_config(struct meson_drm *priv) 78 { 79 unsigned int val; 80 81 /* Setup PLL to output 1.485GHz */ 82 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { 83 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); 84 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00); 85 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); 86 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); 87 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); 88 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); 89 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d); 90 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || 91 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { 92 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); 93 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300); 94 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0xa6212844); 95 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c4d000c); 96 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); 97 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); 98 99 /* Reset PLL */ 100 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, 101 HDMI_PLL_RESET, HDMI_PLL_RESET); 102 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, 103 HDMI_PLL_RESET, 0); 104 } 105 106 /* Poll for lock bit */ 107 regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, 108 (val & HDMI_PLL_LOCK), 10, 0); 109 110 /* Disable VCLK2 */ 111 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); 112 113 /* Disable vid_pll output clock */ 114 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0); 115 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0); 116 /* Enable vid_pll bypass to HDMI pll */ 117 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, 118 VID_PLL_BYPASS, VID_PLL_BYPASS); 119 /* Enable the vid_pll output clock */ 120 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, 121 VID_PLL_EN, VID_PLL_EN); 122 123 /* Setup the VCLK2 divider value to achieve 27MHz */ 124 regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV, 125 VCLK2_DIV_MASK, (55 - 1)); 126 127 /* select vid_pll for vclk2 */ 128 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, 129 VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); 130 /* enable vclk2 gate */ 131 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN); 132 133 /* select vclk_div1 for enci */ 134 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, 135 CTS_ENCI_SEL_MASK, (8 << CTS_ENCI_SEL_SHIFT)); 136 /* select vclk_div1 for vdac */ 137 regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV, 138 CTS_VDAC_SEL_MASK, (8 << CTS_VDAC_SEL_SHIFT)); 139 140 /* release vclk2_div_reset and enable vclk2_div */ 141 regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV, 142 VCLK2_DIV_EN | VCLK2_DIV_RESET, VCLK2_DIV_EN); 143 144 /* enable vclk2_div1 gate */ 145 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, 146 VCLK2_DIV1_EN, VCLK2_DIV1_EN); 147 148 /* reset vclk2 */ 149 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, 150 VCLK2_SOFT_RESET, VCLK2_SOFT_RESET); 151 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, 152 VCLK2_SOFT_RESET, 0); 153 154 /* enable enci_clk */ 155 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, 156 CTS_ENCI_EN, CTS_ENCI_EN); 157 /* enable vdac_clk */ 158 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, 159 CTS_VDAC_EN, CTS_VDAC_EN); 160 } 161 162 void meson_vclk_setup(struct meson_drm *priv, unsigned int target, 163 unsigned int freq) 164 { 165 if (target == MESON_VCLK_TARGET_CVBS && freq == MESON_VCLK_CVBS) 166 meson_venci_cvbs_clock_config(priv); 167 } 168