armada_510.c (3694B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2012 Russell King 4 * 5 * Armada 510 (aka Dove) variant support 6 */ 7#include <linux/clk.h> 8#include <linux/io.h> 9#include <drm/drm_probe_helper.h> 10#include "armada_crtc.h" 11#include "armada_drm.h" 12#include "armada_hw.h" 13 14struct armada510_variant_data { 15 struct clk *clks[4]; 16 struct clk *sel_clk; 17}; 18 19static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) 20{ 21 struct armada510_variant_data *v; 22 struct clk *clk; 23 int idx; 24 25 v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL); 26 if (!v) 27 return -ENOMEM; 28 29 dcrtc->variant_data = v; 30 31 if (dev->of_node) { 32 struct property *prop; 33 const char *s; 34 35 of_property_for_each_string(dev->of_node, "clock-names", prop, 36 s) { 37 if (!strcmp(s, "ext_ref_clk0")) 38 idx = 0; 39 else if (!strcmp(s, "ext_ref_clk1")) 40 idx = 1; 41 else if (!strcmp(s, "plldivider")) 42 idx = 2; 43 else if (!strcmp(s, "axibus")) 44 idx = 3; 45 else 46 continue; 47 48 clk = devm_clk_get(dev, s); 49 if (IS_ERR(clk)) 50 return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : 51 PTR_ERR(clk); 52 v->clks[idx] = clk; 53 } 54 } else { 55 clk = devm_clk_get(dev, "ext_ref_clk1"); 56 if (IS_ERR(clk)) 57 return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : 58 PTR_ERR(clk); 59 60 v->clks[1] = clk; 61 } 62 63 /* 64 * Lower the watermark so to eliminate jitter at higher bandwidths. 65 * Disable SRAM read wait state to avoid system hang with external 66 * clock. 67 */ 68 armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK, 69 dcrtc->base + LCD_CFG_RDREG4F); 70 71 /* Initialise SPU register */ 72 writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, 73 dcrtc->base + LCD_SPU_ADV_REG); 74 75 return 0; 76} 77 78static const u32 armada510_clk_sels[] = { 79 SCLK_510_EXTCLK0, 80 SCLK_510_EXTCLK1, 81 SCLK_510_PLL, 82 SCLK_510_AXI, 83}; 84 85static const struct armada_clocking_params armada510_clocking = { 86 /* HDMI requires -0.6%..+0.5% */ 87 .permillage_min = 994, 88 .permillage_max = 1005, 89 .settable = BIT(0) | BIT(1), 90 .div_max = SCLK_510_INT_DIV_MASK, 91}; 92 93/* 94 * Armada510 specific SCLK register selection. 95 * This gets called with sclk = NULL to test whether the mode is 96 * supportable, and again with sclk != NULL to set the clocks up for 97 * that. The former can return an error, but the latter is expected 98 * not to. 99 */ 100static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, 101 const struct drm_display_mode *mode, uint32_t *sclk) 102{ 103 struct armada510_variant_data *v = dcrtc->variant_data; 104 unsigned long desired_khz = mode->crtc_clock; 105 struct armada_clk_result res; 106 int ret, idx; 107 108 idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking, 109 v->clks, ARRAY_SIZE(v->clks), 110 desired_khz); 111 if (idx < 0) 112 return idx; 113 114 ret = clk_prepare_enable(res.clk); 115 if (ret) 116 return ret; 117 118 if (sclk) { 119 clk_set_rate(res.clk, res.desired_clk_hz); 120 121 *sclk = res.div | armada510_clk_sels[idx]; 122 123 /* We are now using this clock */ 124 v->sel_clk = res.clk; 125 swap(dcrtc->clk, res.clk); 126 } 127 128 clk_disable_unprepare(res.clk); 129 130 return 0; 131} 132 133static void armada510_crtc_disable(struct armada_crtc *dcrtc) 134{ 135 if (dcrtc->clk) { 136 clk_disable_unprepare(dcrtc->clk); 137 dcrtc->clk = NULL; 138 } 139} 140 141static void armada510_crtc_enable(struct armada_crtc *dcrtc, 142 const struct drm_display_mode *mode) 143{ 144 struct armada510_variant_data *v = dcrtc->variant_data; 145 146 if (!dcrtc->clk && v->sel_clk) { 147 if (!WARN_ON(clk_prepare_enable(v->sel_clk))) 148 dcrtc->clk = v->sel_clk; 149 } 150} 151 152const struct armada_variant armada510_ops = { 153 .has_spu_adv_reg = true, 154 .init = armada510_crtc_init, 155 .compute_clock = armada510_crtc_compute_clock, 156 .disable = armada510_crtc_disable, 157 .enable = armada510_crtc_enable, 158};