Files
linux/drivers/gpu/drm/loongson/lsdc_gfxpll.c
Linus Torvalds bf4afc53b7 Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
This was done entirely with mindless brute force, using

    git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
        xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'

to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.

Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.

For the same reason the 'flex' versions will be done as a separate
conversion.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 17:09:51 -08:00

200 lines
5.8 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2023 Loongson Technology Corporation Limited
*/
#include <linux/delay.h>
#include <drm/drm_file.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "lsdc_drv.h"
/*
* GFX PLL is the PLL used by DC, GMC and GPU, the structure of the GFX PLL
* may suffer from change across chip variants.
*
*
* +-------------+ sel_out_dc
* +----| / div_out_0 | _____/ _____ DC
* | +-------------+
* refclk +---------+ +-------+ | +-------------+ sel_out_gmc
* ---+---> | div_ref | ---> | loopc | --+--> | / div_out_1 | _____/ _____ GMC
* | +---------+ +-------+ | +-------------+
* | / * | +-------------+ sel_out_gpu
* | +----| / div_out_2 | _____/ _____ GPU
* | +-------------+
* | ^
* | |
* +--------------------------- bypass ----------------------+
*/
struct loongson_gfxpll_bitmap {
/* Byte 0 ~ Byte 3 */
unsigned div_out_dc : 7; /* 6 : 0 DC output clock divider */
unsigned div_out_gmc : 7; /* 13 : 7 GMC output clock divider */
unsigned div_out_gpu : 7; /* 20 : 14 GPU output clock divider */
unsigned loopc : 9; /* 29 : 21 clock multiplier */
unsigned _reserved_1_ : 2; /* 31 : 30 */
/* Byte 4 ~ Byte 7 */
unsigned div_ref : 7; /* 38 : 32 Input clock divider */
unsigned locked : 1; /* 39 PLL locked indicator */
unsigned sel_out_dc : 1; /* 40 dc output clk enable */
unsigned sel_out_gmc : 1; /* 41 gmc output clk enable */
unsigned sel_out_gpu : 1; /* 42 gpu output clk enable */
unsigned set_param : 1; /* 43 Trigger the update */
unsigned bypass : 1; /* 44 */
unsigned powerdown : 1; /* 45 */
unsigned _reserved_2_ : 18; /* 46 : 63 no use */
};
union loongson_gfxpll_reg_bitmap {
struct loongson_gfxpll_bitmap bitmap;
u32 w[2];
u64 d;
};
static void __gfxpll_rreg(struct loongson_gfxpll *this,
union loongson_gfxpll_reg_bitmap *reg)
{
#if defined(CONFIG_64BIT)
reg->d = readq(this->mmio);
#else
reg->w[0] = readl(this->mmio);
reg->w[1] = readl(this->mmio + 4);
#endif
}
/* Update new parameters to the hardware */
static int loongson_gfxpll_update(struct loongson_gfxpll * const this,
struct loongson_gfxpll_parms const *pin)
{
/* None, TODO */
return 0;
}
static void loongson_gfxpll_get_rates(struct loongson_gfxpll * const this,
unsigned int *dc,
unsigned int *gmc,
unsigned int *gpu)
{
struct loongson_gfxpll_parms *pparms = &this->parms;
union loongson_gfxpll_reg_bitmap gfxpll_reg;
unsigned int pre_output;
unsigned int dc_mhz;
unsigned int gmc_mhz;
unsigned int gpu_mhz;
__gfxpll_rreg(this, &gfxpll_reg);
pparms->div_ref = gfxpll_reg.bitmap.div_ref;
pparms->loopc = gfxpll_reg.bitmap.loopc;
pparms->div_out_dc = gfxpll_reg.bitmap.div_out_dc;
pparms->div_out_gmc = gfxpll_reg.bitmap.div_out_gmc;
pparms->div_out_gpu = gfxpll_reg.bitmap.div_out_gpu;
pre_output = pparms->ref_clock / pparms->div_ref * pparms->loopc;
dc_mhz = pre_output / pparms->div_out_dc / 1000;
gmc_mhz = pre_output / pparms->div_out_gmc / 1000;
gpu_mhz = pre_output / pparms->div_out_gpu / 1000;
if (dc)
*dc = dc_mhz;
if (gmc)
*gmc = gmc_mhz;
if (gpu)
*gpu = gpu_mhz;
}
static void loongson_gfxpll_print(struct loongson_gfxpll * const this,
struct drm_printer *p,
bool verbose)
{
struct loongson_gfxpll_parms *parms = &this->parms;
unsigned int dc, gmc, gpu;
if (verbose) {
drm_printf(p, "reference clock: %u\n", parms->ref_clock);
drm_printf(p, "div_ref = %u\n", parms->div_ref);
drm_printf(p, "loopc = %u\n", parms->loopc);
drm_printf(p, "div_out_dc = %u\n", parms->div_out_dc);
drm_printf(p, "div_out_gmc = %u\n", parms->div_out_gmc);
drm_printf(p, "div_out_gpu = %u\n", parms->div_out_gpu);
}
this->funcs->get_rates(this, &dc, &gmc, &gpu);
drm_printf(p, "dc: %uMHz, gmc: %uMHz, gpu: %uMHz\n", dc, gmc, gpu);
}
/* GFX (DC, GPU, GMC) PLL initialization and destroy function */
static void loongson_gfxpll_fini(struct drm_device *ddev, void *data)
{
struct loongson_gfxpll *this = (struct loongson_gfxpll *)data;
iounmap(this->mmio);
kfree(this);
}
static int loongson_gfxpll_init(struct loongson_gfxpll * const this)
{
struct loongson_gfxpll_parms *pparms = &this->parms;
struct drm_printer printer = drm_info_printer(this->ddev->dev);
pparms->ref_clock = LSDC_PLL_REF_CLK_KHZ;
this->mmio = ioremap(this->reg_base, this->reg_size);
if (IS_ERR_OR_NULL(this->mmio))
return -ENOMEM;
this->funcs->print(this, &printer, false);
return 0;
}
static const struct loongson_gfxpll_funcs lsdc_gmc_gpu_funcs = {
.init = loongson_gfxpll_init,
.update = loongson_gfxpll_update,
.get_rates = loongson_gfxpll_get_rates,
.print = loongson_gfxpll_print,
};
int loongson_gfxpll_create(struct drm_device *ddev,
struct loongson_gfxpll **ppout)
{
struct lsdc_device *ldev = to_lsdc(ddev);
const struct loongson_gfx_desc *gfx = to_loongson_gfx(ldev->descp);
struct loongson_gfxpll *this;
int ret;
this = kzalloc_obj(*this);
if (IS_ERR_OR_NULL(this))
return -ENOMEM;
this->ddev = ddev;
this->reg_size = gfx->gfxpll.reg_size;
this->reg_base = gfx->conf_reg_base + gfx->gfxpll.reg_offset;
this->funcs = &lsdc_gmc_gpu_funcs;
ret = this->funcs->init(this);
if (unlikely(ret)) {
kfree(this);
return ret;
}
*ppout = this;
return drmm_add_action_or_reset(ddev, loongson_gfxpll_fini, this);
}