brintos

brintos / linux-shallow public Read only

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