1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 296f60e37SRussell King /* 396f60e37SRussell King * Copyright (C) 2012 Russell King 496f60e37SRussell King * 596f60e37SRussell King * Armada 510 (aka Dove) variant support 696f60e37SRussell King */ 796f60e37SRussell King #include <linux/clk.h> 896f60e37SRussell King #include <linux/io.h> 9*73289afeSVille Syrjälä #include <linux/of.h> 10fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 1196f60e37SRussell King #include "armada_crtc.h" 1296f60e37SRussell King #include "armada_drm.h" 1396f60e37SRussell King #include "armada_hw.h" 1496f60e37SRussell King 151ba246f2SRussell King struct armada510_variant_data { 161ba246f2SRussell King struct clk *clks[4]; 171ba246f2SRussell King struct clk *sel_clk; 181ba246f2SRussell King }; 191ba246f2SRussell King 203ecea269SRussell King static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) 2196f60e37SRussell King { 221ba246f2SRussell King struct armada510_variant_data *v; 233ecea269SRussell King struct clk *clk; 241ba246f2SRussell King int idx; 2596f60e37SRussell King 261ba246f2SRussell King v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL); 271ba246f2SRussell King if (!v) 281ba246f2SRussell King return -ENOMEM; 291ba246f2SRussell King 301ba246f2SRussell King dcrtc->variant_data = v; 311ba246f2SRussell King 321ba246f2SRussell King if (dev->of_node) { 331ba246f2SRussell King struct property *prop; 341ba246f2SRussell King const char *s; 351ba246f2SRussell King 361ba246f2SRussell King of_property_for_each_string(dev->of_node, "clock-names", prop, 371ba246f2SRussell King s) { 381ba246f2SRussell King if (!strcmp(s, "ext_ref_clk0")) 391ba246f2SRussell King idx = 0; 401ba246f2SRussell King else if (!strcmp(s, "ext_ref_clk1")) 411ba246f2SRussell King idx = 1; 421ba246f2SRussell King else if (!strcmp(s, "plldivider")) 431ba246f2SRussell King idx = 2; 441ba246f2SRussell King else if (!strcmp(s, "axibus")) 451ba246f2SRussell King idx = 3; 461ba246f2SRussell King else 471ba246f2SRussell King continue; 481ba246f2SRussell King 491ba246f2SRussell King clk = devm_clk_get(dev, s); 501ba246f2SRussell King if (IS_ERR(clk)) 511ba246f2SRussell King return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : 521ba246f2SRussell King PTR_ERR(clk); 531ba246f2SRussell King v->clks[idx] = clk; 541ba246f2SRussell King } 551ba246f2SRussell King } else { 56fe424872SRussell King clk = devm_clk_get(dev, "ext_ref_clk1"); 573ecea269SRussell King if (IS_ERR(clk)) 581ba246f2SRussell King return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : 591ba246f2SRussell King PTR_ERR(clk); 6096f60e37SRussell King 611ba246f2SRussell King v->clks[1] = clk; 621ba246f2SRussell King } 6396f60e37SRussell King 645a6cbce8SRussell King /* 655a6cbce8SRussell King * Lower the watermark so to eliminate jitter at higher bandwidths. 665a6cbce8SRussell King * Disable SRAM read wait state to avoid system hang with external 675a6cbce8SRussell King * clock. 685a6cbce8SRussell King */ 695a6cbce8SRussell King armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK, 705a6cbce8SRussell King dcrtc->base + LCD_CFG_RDREG4F); 713ecea269SRussell King 724e4b3563SRussell King /* Initialise SPU register */ 734e4b3563SRussell King writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, 744e4b3563SRussell King dcrtc->base + LCD_SPU_ADV_REG); 754e4b3563SRussell King 7696f60e37SRussell King return 0; 7796f60e37SRussell King } 7896f60e37SRussell King 791ba246f2SRussell King static const u32 armada510_clk_sels[] = { 801ba246f2SRussell King SCLK_510_EXTCLK0, 811ba246f2SRussell King SCLK_510_EXTCLK1, 821ba246f2SRussell King SCLK_510_PLL, 831ba246f2SRussell King SCLK_510_AXI, 841ba246f2SRussell King }; 851ba246f2SRussell King 861ba246f2SRussell King static const struct armada_clocking_params armada510_clocking = { 871ba246f2SRussell King /* HDMI requires -0.6%..+0.5% */ 881ba246f2SRussell King .permillage_min = 994, 891ba246f2SRussell King .permillage_max = 1005, 901ba246f2SRussell King .settable = BIT(0) | BIT(1), 911ba246f2SRussell King .div_max = SCLK_510_INT_DIV_MASK, 921ba246f2SRussell King }; 931ba246f2SRussell King 9496f60e37SRussell King /* 9596f60e37SRussell King * Armada510 specific SCLK register selection. 9696f60e37SRussell King * This gets called with sclk = NULL to test whether the mode is 9796f60e37SRussell King * supportable, and again with sclk != NULL to set the clocks up for 9896f60e37SRussell King * that. The former can return an error, but the latter is expected 9996f60e37SRussell King * not to. 10096f60e37SRussell King */ 10196f60e37SRussell King static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, 10296f60e37SRussell King const struct drm_display_mode *mode, uint32_t *sclk) 10396f60e37SRussell King { 1041ba246f2SRussell King struct armada510_variant_data *v = dcrtc->variant_data; 1051ba246f2SRussell King unsigned long desired_khz = mode->crtc_clock; 1061ba246f2SRussell King struct armada_clk_result res; 1071ba246f2SRussell King int ret, idx; 10896f60e37SRussell King 1091ba246f2SRussell King idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking, 1101ba246f2SRussell King v->clks, ARRAY_SIZE(v->clks), 1111ba246f2SRussell King desired_khz); 1121ba246f2SRussell King if (idx < 0) 1131ba246f2SRussell King return idx; 11496f60e37SRussell King 1151ba246f2SRussell King ret = clk_prepare_enable(res.clk); 11696f60e37SRussell King if (ret) 11796f60e37SRussell King return ret; 11896f60e37SRussell King 11996f60e37SRussell King if (sclk) { 1201ba246f2SRussell King clk_set_rate(res.clk, res.desired_clk_hz); 12196f60e37SRussell King 1221ba246f2SRussell King *sclk = res.div | armada510_clk_sels[idx]; 12396f60e37SRussell King 1241ba246f2SRussell King /* We are now using this clock */ 1251ba246f2SRussell King v->sel_clk = res.clk; 1261ba246f2SRussell King swap(dcrtc->clk, res.clk); 12796f60e37SRussell King } 12896f60e37SRussell King 1291ba246f2SRussell King clk_disable_unprepare(res.clk); 1301ba246f2SRussell King 13196f60e37SRussell King return 0; 13296f60e37SRussell King } 13396f60e37SRussell King 134a0fbb35eSRussell King static void armada510_crtc_disable(struct armada_crtc *dcrtc) 135a0fbb35eSRussell King { 1361ba246f2SRussell King if (dcrtc->clk) { 137a0fbb35eSRussell King clk_disable_unprepare(dcrtc->clk); 1381ba246f2SRussell King dcrtc->clk = NULL; 139a0fbb35eSRussell King } 140a0fbb35eSRussell King } 141a0fbb35eSRussell King 142a0fbb35eSRussell King static void armada510_crtc_enable(struct armada_crtc *dcrtc, 143a0fbb35eSRussell King const struct drm_display_mode *mode) 144a0fbb35eSRussell King { 1451ba246f2SRussell King struct armada510_variant_data *v = dcrtc->variant_data; 1461ba246f2SRussell King 1471ba246f2SRussell King if (!dcrtc->clk && v->sel_clk) { 1481ba246f2SRussell King if (!WARN_ON(clk_prepare_enable(v->sel_clk))) 1491ba246f2SRussell King dcrtc->clk = v->sel_clk; 150a0fbb35eSRussell King } 151a0fbb35eSRussell King } 152a0fbb35eSRussell King 15396f60e37SRussell King const struct armada_variant armada510_ops = { 15496f60e37SRussell King .has_spu_adv_reg = true, 15542e62ba7SRussell King .init = armada510_crtc_init, 15642e62ba7SRussell King .compute_clock = armada510_crtc_compute_clock, 157a0fbb35eSRussell King .disable = armada510_crtc_disable, 158a0fbb35eSRussell King .enable = armada510_crtc_enable, 15996f60e37SRussell King }; 160