1*96f60e37SRussell King /* 2*96f60e37SRussell King * Copyright (C) 2012 Russell King 3*96f60e37SRussell King * 4*96f60e37SRussell King * This program is free software; you can redistribute it and/or modify 5*96f60e37SRussell King * it under the terms of the GNU General Public License version 2 as 6*96f60e37SRussell King * published by the Free Software Foundation. 7*96f60e37SRussell King * 8*96f60e37SRussell King * Armada 510 (aka Dove) variant support 9*96f60e37SRussell King */ 10*96f60e37SRussell King #include <linux/clk.h> 11*96f60e37SRussell King #include <linux/io.h> 12*96f60e37SRussell King #include <drm/drmP.h> 13*96f60e37SRussell King #include <drm/drm_crtc_helper.h> 14*96f60e37SRussell King #include "armada_crtc.h" 15*96f60e37SRussell King #include "armada_drm.h" 16*96f60e37SRussell King #include "armada_hw.h" 17*96f60e37SRussell King 18*96f60e37SRussell King static int armada510_init(struct armada_private *priv, struct device *dev) 19*96f60e37SRussell King { 20*96f60e37SRussell King priv->extclk[0] = devm_clk_get(dev, "ext_ref_clk_1"); 21*96f60e37SRussell King 22*96f60e37SRussell King if (IS_ERR(priv->extclk[0]) && PTR_ERR(priv->extclk[0]) == -ENOENT) 23*96f60e37SRussell King priv->extclk[0] = ERR_PTR(-EPROBE_DEFER); 24*96f60e37SRussell King 25*96f60e37SRussell King return PTR_RET(priv->extclk[0]); 26*96f60e37SRussell King } 27*96f60e37SRussell King 28*96f60e37SRussell King static int armada510_crtc_init(struct armada_crtc *dcrtc) 29*96f60e37SRussell King { 30*96f60e37SRussell King /* Lower the watermark so to eliminate jitter at higher bandwidths */ 31*96f60e37SRussell King armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); 32*96f60e37SRussell King return 0; 33*96f60e37SRussell King } 34*96f60e37SRussell King 35*96f60e37SRussell King /* 36*96f60e37SRussell King * Armada510 specific SCLK register selection. 37*96f60e37SRussell King * This gets called with sclk = NULL to test whether the mode is 38*96f60e37SRussell King * supportable, and again with sclk != NULL to set the clocks up for 39*96f60e37SRussell King * that. The former can return an error, but the latter is expected 40*96f60e37SRussell King * not to. 41*96f60e37SRussell King * 42*96f60e37SRussell King * We currently are pretty rudimentary here, always selecting 43*96f60e37SRussell King * EXT_REF_CLK_1 for LCD0 and erroring LCD1. This needs improvement! 44*96f60e37SRussell King */ 45*96f60e37SRussell King static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, 46*96f60e37SRussell King const struct drm_display_mode *mode, uint32_t *sclk) 47*96f60e37SRussell King { 48*96f60e37SRussell King struct armada_private *priv = dcrtc->crtc.dev->dev_private; 49*96f60e37SRussell King struct clk *clk = priv->extclk[0]; 50*96f60e37SRussell King int ret; 51*96f60e37SRussell King 52*96f60e37SRussell King if (dcrtc->num == 1) 53*96f60e37SRussell King return -EINVAL; 54*96f60e37SRussell King 55*96f60e37SRussell King if (IS_ERR(clk)) 56*96f60e37SRussell King return PTR_ERR(clk); 57*96f60e37SRussell King 58*96f60e37SRussell King if (dcrtc->clk != clk) { 59*96f60e37SRussell King ret = clk_prepare_enable(clk); 60*96f60e37SRussell King if (ret) 61*96f60e37SRussell King return ret; 62*96f60e37SRussell King dcrtc->clk = clk; 63*96f60e37SRussell King } 64*96f60e37SRussell King 65*96f60e37SRussell King if (sclk) { 66*96f60e37SRussell King uint32_t rate, ref, div; 67*96f60e37SRussell King 68*96f60e37SRussell King rate = mode->clock * 1000; 69*96f60e37SRussell King ref = clk_round_rate(clk, rate); 70*96f60e37SRussell King div = DIV_ROUND_UP(ref, rate); 71*96f60e37SRussell King if (div < 1) 72*96f60e37SRussell King div = 1; 73*96f60e37SRussell King 74*96f60e37SRussell King clk_set_rate(clk, ref); 75*96f60e37SRussell King *sclk = div | SCLK_510_EXTCLK1; 76*96f60e37SRussell King } 77*96f60e37SRussell King 78*96f60e37SRussell King return 0; 79*96f60e37SRussell King } 80*96f60e37SRussell King 81*96f60e37SRussell King const struct armada_variant armada510_ops = { 82*96f60e37SRussell King .has_spu_adv_reg = true, 83*96f60e37SRussell King .init = armada510_init, 84*96f60e37SRussell King .crtc_init = armada510_crtc_init, 85*96f60e37SRussell King .crtc_compute_clock = armada510_crtc_compute_clock, 86*96f60e37SRussell King }; 87