drivers/gpu/drm/sprd/megacores_pll.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/sprd/megacores_pll.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/sprd/megacores_pll.c
Extension
.c
Size
8374 bytes
Lines
306
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2020 Unisoc Inc.
 */

#include <asm/div64.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/regmap.h>
#include <linux/string.h>

#include "sprd_dsi.h"

#define L						0
#define H						1
#define CLK						0
#define DATA					1
#define INFINITY				0xffffffff
#define MIN_OUTPUT_FREQ			(100)

#define AVERAGE(a, b) (min(a, b) + abs((b) - (a)) / 2)

/* sharkle */
#define VCO_BAND_LOW	750
#define VCO_BAND_MID	1100
#define VCO_BAND_HIGH	1500
#define PHY_REF_CLK	26000

static int dphy_calc_pll_param(struct dphy_pll *pll)
{
	const u32 khz = 1000;
	const u32 mhz = 1000000;
	const unsigned long long factor = 100;
	unsigned long long tmp;
	int i;

	pll->potential_fvco = pll->freq / khz;
	pll->ref_clk = PHY_REF_CLK / khz;

	for (i = 0; i < 4; ++i) {
		if (pll->potential_fvco >= VCO_BAND_LOW &&
		    pll->potential_fvco <= VCO_BAND_HIGH) {
			pll->fvco = pll->potential_fvco;
			pll->out_sel = BIT(i);
			break;
		}
		pll->potential_fvco <<= 1;
	}
	if (pll->fvco == 0)
		return -EINVAL;

	if (pll->fvco >= VCO_BAND_LOW && pll->fvco <= VCO_BAND_MID) {
		/* vco band control */
		pll->vco_band = 0x0;
		/* low pass filter control */
		pll->lpf_sel = 1;
	} else if (pll->fvco > VCO_BAND_MID && pll->fvco <= VCO_BAND_HIGH) {
		pll->vco_band = 0x1;
		pll->lpf_sel = 0;
	} else {
		return -EINVAL;
	}

	pll->nint = pll->fvco / pll->ref_clk;
	tmp = pll->fvco * factor * mhz;
	do_div(tmp, pll->ref_clk);
	tmp = tmp - pll->nint * factor * mhz;
	tmp *= BIT(20);
	do_div(tmp, 100000000);
	pll->kint = (u32)tmp;
	pll->refin = 3; /* pre-divider bypass */
	pll->sdm_en = true; /* use fraction N PLL */
	pll->fdk_s = 0x1; /* fraction */
	pll->cp_s = 0x0;
	pll->det_delay = 0x1;

	return 0;
}

static void dphy_set_pll_reg(struct dphy_pll *pll, struct regmap *regmap)
{
	u8 reg_val[9] = {0};
	int i;

	u8 reg_addr[] = {
		0x03, 0x04, 0x06, 0x08, 0x09,
		0x0a, 0x0b, 0x0e, 0x0f
	};

Annotation

Implementation Notes