Merge tag 'LA.UM.9.12.r1-15500-SMxx50.QSSI13.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.19 into android13-4.19-kona
"LA.UM.9.12.r1-15500-SMxx50.QSSI13.0" * tag 'LA.UM.9.12.r1-15500-SMxx50.QSSI13.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.19: ANDROID: usb: f_accessory: Avoid bitfields for shared variables qcedev: vote for crypto clocks during module close msm-4.19: Compilation fix for SDLLVM toolchain 16.0 Makefile: Use Python2 for compilation soc: qcom: provide apis for pcode and feature string defconfig: Enable pwm support for SCUBA PWM: Add support for PWM driver clk: qcom: gcc-scuba: Add gcc_pwm0_xo512_div_clk_src clk support bindings: clock: qcom: Add gcc_pwm0_xo512_div_clk_src clock id soc: qcom: socinfo: Add sku sysfs support soc: qcom: socinfo: Add revision 16 support in socinfo structure msm: adsprpc: Handle UAF in fastrpc internal munmap msm: kgsl: Do not capture DTCM on gmu boot failure sched/walt: don't panic for accounting issues tap: tap_open(): correctly initialize socket uid tun: tun_chr_open(): correctly initialize socket uid net: add sock_init_data_uid() Conflicts: Makefile Change-Id: I55976e2f6495d6f1190eeaf8e4eda6fa44be2083
This commit is contained in:
commit
1a352c10f2
20 changed files with 1080 additions and 37 deletions
1
arch/arm64/configs/vendor/bengal_defconfig
vendored
1
arch/arm64/configs/vendor/bengal_defconfig
vendored
|
@ -630,6 +630,7 @@ CONFIG_IIO=y
|
|||
CONFIG_QCOM_SPMI_ADC5=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_QTI_LPG=y
|
||||
CONFIG_PWM_QCOM=y
|
||||
CONFIG_ARM_GIC_V3_ACL=y
|
||||
CONFIG_QCOM_MPM=y
|
||||
CONFIG_PHY_XGENE=y
|
||||
|
|
|
@ -415,8 +415,8 @@ struct fastrpc_mmap {
|
|||
int uncached;
|
||||
int secure;
|
||||
uintptr_t attr;
|
||||
bool is_filemap;
|
||||
/* flag to indicate map used in process init */
|
||||
bool is_filemap; /* flag to indicate map used in process init */
|
||||
unsigned int ctx_refs; /* Indicates reference count for context map */
|
||||
};
|
||||
|
||||
enum fastrpc_perfkeys {
|
||||
|
@ -849,7 +849,7 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
|
|||
hlist_for_each_entry_safe(map, n, &me->maps, hn) {
|
||||
if (map->refs == 1 && map->raddr == va &&
|
||||
map->raddr + map->len == va + len &&
|
||||
/* Remove map if not used in process initialization*/
|
||||
/* Remove map if not used in process initialization */
|
||||
!map->is_filemap) {
|
||||
match = map;
|
||||
hlist_del_init(&map->hn);
|
||||
|
@ -862,9 +862,10 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
|
|||
return 0;
|
||||
}
|
||||
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
|
||||
if (map->refs == 1 && map->raddr == va &&
|
||||
map->raddr + map->len == va + len &&
|
||||
/* Remove map if not used in process initialization*/
|
||||
/* Remove if only one reference map and no context map */
|
||||
if (map->refs == 1 && !map->ctx_refs &&
|
||||
map->raddr == va && map->raddr + map->len == va + len &&
|
||||
/* Remove map if not used in process initialization */
|
||||
!map->is_filemap) {
|
||||
match = map;
|
||||
hlist_del_init(&map->hn);
|
||||
|
@ -903,14 +904,14 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
|
|||
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
|
||||
spin_lock(&me->hlock);
|
||||
map->refs--;
|
||||
if (!map->refs)
|
||||
if (!map->refs && !map->ctx_refs)
|
||||
hlist_del_init(&map->hn);
|
||||
spin_unlock(&me->hlock);
|
||||
if (map->refs > 0)
|
||||
return;
|
||||
} else {
|
||||
map->refs--;
|
||||
if (!map->refs)
|
||||
if (!map->refs && !map->ctx_refs)
|
||||
hlist_del_init(&map->hn);
|
||||
if (map->refs > 0 && !flags)
|
||||
return;
|
||||
|
@ -1008,6 +1009,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
|
|||
map->fd = fd;
|
||||
map->attr = attr;
|
||||
map->is_filemap = false;
|
||||
map->ctx_refs = 0;
|
||||
if (mflags == ADSP_MMAP_HEAP_ADDR ||
|
||||
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
|
||||
map->apps = me;
|
||||
|
@ -1533,8 +1535,11 @@ static void context_free(struct smq_invoke_ctx *ctx)
|
|||
spin_unlock(&ctx->fl->hlock);
|
||||
|
||||
mutex_lock(&ctx->fl->map_mutex);
|
||||
for (i = 0; i < nbufs; ++i)
|
||||
for (i = 0; i < nbufs; ++i) {
|
||||
if (ctx->maps[i] && ctx->maps[i]->ctx_refs)
|
||||
ctx->maps[i]->ctx_refs--;
|
||||
fastrpc_mmap_free(ctx->maps[i], 0);
|
||||
}
|
||||
mutex_unlock(&ctx->fl->map_mutex);
|
||||
|
||||
fastrpc_buf_free(ctx->buf, 1);
|
||||
|
@ -1757,6 +1762,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
|
|||
err = fastrpc_mmap_create(ctx->fl, ctx->fds[i],
|
||||
ctx->attrs[i], buf, len,
|
||||
mflags, &ctx->maps[i]);
|
||||
if (ctx->maps[i])
|
||||
ctx->maps[i]->ctx_refs++;
|
||||
mutex_unlock(&ctx->fl->map_mutex);
|
||||
if (err)
|
||||
goto bail;
|
||||
|
@ -1774,9 +1781,14 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
|
|||
err = fastrpc_mmap_create(ctx->fl, ctx->fds[i],
|
||||
FASTRPC_ATTR_NOVA, 0, 0, dmaflags,
|
||||
&ctx->maps[i]);
|
||||
if (!err && ctx->maps[i])
|
||||
ctx->maps[i]->ctx_refs++;
|
||||
if (err) {
|
||||
for (j = bufs; j < i; j++)
|
||||
for (j = bufs; j < i; j++) {
|
||||
if (ctx->maps[j] && ctx->maps[j]->ctx_refs)
|
||||
ctx->maps[j]->ctx_refs--;
|
||||
fastrpc_mmap_free(ctx->maps[j], 0);
|
||||
}
|
||||
mutex_unlock(&ctx->fl->map_mutex);
|
||||
goto bail;
|
||||
}
|
||||
|
@ -2059,6 +2071,8 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
|
|||
goto bail;
|
||||
} else {
|
||||
mutex_lock(&ctx->fl->map_mutex);
|
||||
if (ctx->maps[i]->ctx_refs)
|
||||
ctx->maps[i]->ctx_refs--;
|
||||
fastrpc_mmap_free(ctx->maps[i], 0);
|
||||
mutex_unlock(&ctx->fl->map_mutex);
|
||||
ctx->maps[i] = NULL;
|
||||
|
@ -2070,10 +2084,13 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
|
|||
if (!fdlist[i])
|
||||
break;
|
||||
if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], 0, 0,
|
||||
0, 0, &mmap))
|
||||
0, 0, &mmap)) {
|
||||
if (mmap && mmap->ctx_refs)
|
||||
mmap->ctx_refs--;
|
||||
fastrpc_mmap_free(mmap, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ctx->fl->map_mutex);
|
||||
if (ctx->crc && crclist && rpra)
|
||||
K_COPY_TO_USER(err, kernel, ctx->crc,
|
||||
|
|
|
@ -2246,6 +2246,19 @@ static struct clk_regmap_div gcc_disp_gpll0_clk_src = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap_div gcc_pwm0_xo512_div_clk_src = {
|
||||
.reg = 0x20030,
|
||||
.shift = 0,
|
||||
.width = 9,
|
||||
.clkr.hw.init = &(const struct clk_init_data) {
|
||||
.name = "gcc_pwm0_xo512_div_clk_src",
|
||||
.parent_names =
|
||||
(const char *[]){ "bi_tcxo" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_regmap_div_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_disp_gpll0_div_clk_src = {
|
||||
.halt_check = BRANCH_HALT_DELAY,
|
||||
.clkr = {
|
||||
|
@ -2522,6 +2535,11 @@ static struct clk_branch gcc_pwm0_xo512_clk = {
|
|||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_pwm0_xo512_clk",
|
||||
.parent_names = (const char *[]){
|
||||
"gcc_pwm0_xo512_div_clk_src",
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_branch2_ops,
|
||||
},
|
||||
},
|
||||
|
@ -3178,6 +3196,7 @@ static struct clk_regmap *gcc_scuba_clocks[] = {
|
|||
[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
|
||||
[GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
|
||||
[GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
|
||||
[GCC_PWM0_XO512_DIV_CLK_SRC] = &gcc_pwm0_xo512_div_clk_src.clkr,
|
||||
[GCC_GPU_IREF_CLK] = &gcc_gpu_iref_clk.clkr,
|
||||
[GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
|
||||
[GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
|
||||
|
|
|
@ -2283,8 +2283,11 @@ static int qcedev_remove(struct platform_device *pdev)
|
|||
podev = platform_get_drvdata(pdev);
|
||||
if (!podev)
|
||||
return 0;
|
||||
|
||||
qcedev_ce_high_bw_req(podev, true);
|
||||
if (podev->qce)
|
||||
qce_close(podev->qce);
|
||||
qcedev_ce_high_bw_req(podev, false);
|
||||
|
||||
if (podev->platform_support.bus_scale_table != NULL)
|
||||
msm_bus_scale_unregister_client(podev->bus_scale_handle);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/* soc/qcom/cmd-db.h needs types.h */
|
||||
|
@ -388,19 +389,11 @@ static int a6xx_gmu_start(struct kgsl_device *device)
|
|||
gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0);
|
||||
/* Make sure the request completes before continuing */
|
||||
wmb();
|
||||
|
||||
if (timed_poll_check(device,
|
||||
A6XX_GMU_CM3_FW_INIT_RESULT,
|
||||
val, GMU_START_TIMEOUT, mask)) {
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* The breadcrumb is written to a gmu virtual mapping
|
||||
* which points to dtcm byte offset 0x3fdc.
|
||||
*/
|
||||
gmu_core_regread(device,
|
||||
A6XX_GMU_CM3_DTCM_START + (0x3fdc >> 2), &val);
|
||||
dev_err(&gmu->pdev->dev, "GMU doesn't boot: 0x%x\n", val);
|
||||
|
||||
dev_err(&gmu->pdev->dev, "GMU doesn't boot\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ int openChannel(struct i2c_client *clt)
|
|||
return OK;
|
||||
}
|
||||
|
||||
struct device *getDev()
|
||||
struct device *getDev(void)
|
||||
{
|
||||
if (client != NULL)
|
||||
return &(client->dev);
|
||||
|
@ -90,7 +90,7 @@ struct device *getDev()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct i2c_client *getClient()
|
||||
struct i2c_client *getClient(void)
|
||||
{
|
||||
if (client != NULL)
|
||||
return client;
|
||||
|
|
|
@ -92,7 +92,7 @@ int elapsedNanosecond(struct StopWatch *w)
|
|||
return result;
|
||||
}
|
||||
|
||||
char *timestamp()
|
||||
char *timestamp(void)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
|
|
|
@ -525,7 +525,7 @@ static int tap_open(struct inode *inode, struct file *file)
|
|||
q->sock.state = SS_CONNECTED;
|
||||
q->sock.file = file;
|
||||
q->sock.ops = &tap_socket_ops;
|
||||
sock_init_data(&q->sock, &q->sk);
|
||||
sock_init_data_uid(&q->sock, &q->sk, inode->i_uid);
|
||||
q->sk.sk_write_space = tap_sock_write_space;
|
||||
q->sk.sk_destruct = tap_sock_destruct;
|
||||
q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP;
|
||||
|
|
|
@ -3349,7 +3349,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
|
|||
tfile->socket.file = file;
|
||||
tfile->socket.ops = &tun_socket_ops;
|
||||
|
||||
sock_init_data(&tfile->socket, &tfile->sk);
|
||||
sock_init_data_uid(&tfile->socket, &tfile->sk, inode->i_uid);
|
||||
|
||||
tfile->sk.sk_write_space = tun_sock_write_space;
|
||||
tfile->sk.sk_sndbuf = INT_MAX;
|
||||
|
|
|
@ -520,4 +520,14 @@ config PWM_ZX
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-zx.
|
||||
|
||||
config PWM_QCOM
|
||||
tristate "Qualcomm Technologies, Inc. PWM support"
|
||||
depends on ARCH_QCOM
|
||||
help
|
||||
Generic PWM framework driver for the PWM controller found on
|
||||
Qualcomm Technologies Inc. SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-qcom.
|
||||
|
||||
endif
|
||||
|
|
|
@ -33,6 +33,7 @@ obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o
|
|||
obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
|
||||
obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
|
||||
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
|
||||
obj-$(CONFIG_PWM_QCOM) += pwm-qcom.o
|
||||
obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o
|
||||
obj-$(CONFIG_PWM_QTI_LPG) += pwm-qti-lpg.o
|
||||
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
|
||||
|
|
667
drivers/pwm/pwm-qcom.c
Normal file
667
drivers/pwm/pwm-qcom.c
Normal file
|
@ -0,0 +1,667 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#define PERIOD_TO_HZ(period_ns) ((1 * 1000000000UL) / period_ns)
|
||||
#define FRAME_NUM_MAX_LEN 9
|
||||
|
||||
/* Offsets */
|
||||
#define PWM_TOPCTL0 0x0
|
||||
|
||||
/* offsets per frame */
|
||||
#define PWM_CTL0 0x0
|
||||
#define PWM_CTL1 0x4
|
||||
#define PWM_CTL2 0x8
|
||||
#define PWM_CYC_CFG 0xC
|
||||
#define PWM_UPDATE 0x10
|
||||
#define PWM_PERIOD_CNT 0x14
|
||||
|
||||
enum {
|
||||
ENABLE_STATUS0,
|
||||
ENABLE_STATUS1,
|
||||
|
||||
ENABLE_STATUS_REG_SIZE,
|
||||
};
|
||||
|
||||
struct pdm_pwm_priv_data {
|
||||
unsigned int max_channels;
|
||||
const u16 *status_reg_offsets;
|
||||
};
|
||||
|
||||
/*
|
||||
*struct pdm_pwm_frames - Information regarding per pdm frame
|
||||
* @frame_id: Id number associated with each frame.
|
||||
* @reg_offset: offset of each frame from base pdm.
|
||||
* @current_period_ns: Current period of the particular frame.
|
||||
* @current_duty_ns: Current duty cycle of the particular frame.
|
||||
* @current_freq: Current frequency of frame.
|
||||
* @freq_set: This bool flag is responsible for setting period once per frame.
|
||||
* @mutex: mutex lock per frame.
|
||||
*/
|
||||
struct pdm_pwm_frames {
|
||||
u32 frame_id;
|
||||
u32 reg_offset;
|
||||
u64 current_period_ns;
|
||||
u64 current_duty_ns;
|
||||
unsigned long current_freq;
|
||||
bool is_enabled;
|
||||
bool freq_set;
|
||||
struct mutex frame_lock; /* PWM per frame lock */
|
||||
struct pdm_pwm_chip *pwm_chip;
|
||||
};
|
||||
|
||||
/*
|
||||
*struct pdm_pwm_chip - Information regarding per pdm
|
||||
* @pwm_chip: information per pdm.
|
||||
* @regmap: regmap of each pdm.
|
||||
* @device: pdm device.
|
||||
* @pdm_pwm_frames: structure for all frames of each pdm.
|
||||
* @pdm_ahb_clk: pdm clock for enabling pdm block
|
||||
* @pwm_core_clk: pwm clock for enabling each pwm.
|
||||
* @mutex: mutex lock per frame.
|
||||
* @pwm_core_rate: core rate of pwm_core__clk.
|
||||
* @num_frames: number of frames in each pdm.
|
||||
*/
|
||||
struct pdm_pwm_chip {
|
||||
struct pwm_chip pwm_chip;
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct pdm_pwm_frames *frames;
|
||||
struct clk *pdm_ahb_clk;
|
||||
struct clk *pwm_core_clk;
|
||||
struct pdm_pwm_priv_data *priv_data;
|
||||
/* This lock to be used for Enable/Disable as it is per PWM channel */
|
||||
struct mutex lock;
|
||||
unsigned long pwm_core_rate;
|
||||
u32 num_frames;
|
||||
};
|
||||
|
||||
static int __pdm_pwm_calc_pwm_frequency(struct pdm_pwm_chip *chip,
|
||||
int period_ns, u32 hw_idx)
|
||||
{
|
||||
unsigned long cyc_cfg, freq;
|
||||
int ret;
|
||||
|
||||
/* PWM client could set the period only once, due to HW limitation. */
|
||||
if (chip->frames[hw_idx].freq_set)
|
||||
return 0;
|
||||
|
||||
freq = PERIOD_TO_HZ(period_ns);
|
||||
if (!freq) {
|
||||
pr_err("Frequency cannot be Zero\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (freq > (chip->pwm_core_rate >> 1) ||
|
||||
freq <= (chip->pwm_core_rate >> 16)) {
|
||||
pr_debug("Freq %ld is not in range Max=%ld Min=%ld\n", freq,
|
||||
(chip->pwm_core_rate >> 1), (chip->pwm_core_rate >> 16) + 1);
|
||||
return -ERANGE;
|
||||
}
|
||||
cyc_cfg = DIV_ROUND_CLOSEST(chip->pwm_core_rate, freq) - 1;
|
||||
|
||||
ret = regmap_update_bits(chip->regmap,
|
||||
chip->frames[hw_idx].reg_offset + PWM_CYC_CFG,
|
||||
GENMASK(15, 0), cyc_cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chip->frames[hw_idx].current_freq = freq;
|
||||
chip->frames[hw_idx].freq_set = true;
|
||||
chip->frames[hw_idx].current_period_ns = period_ns;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pdm_pwm_get_state(struct pwm_chip *pwm_chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct pdm_pwm_chip *chip = container_of(pwm_chip,
|
||||
struct pdm_pwm_chip, pwm_chip);
|
||||
|
||||
state->enabled = chip->frames[pwm->hwpwm].is_enabled;
|
||||
state->period = chip->frames[pwm->hwpwm].current_period_ns;
|
||||
state->duty_cycle = chip->frames[pwm->hwpwm].current_duty_ns;
|
||||
|
||||
}
|
||||
|
||||
static int pdm_pwm_config(struct pdm_pwm_chip *chip, u32 hw_idx,
|
||||
int duty_ns, int period_ns)
|
||||
{
|
||||
unsigned long ctl1;
|
||||
int current_period = period_ns, ret;
|
||||
u32 cyc_cfg;
|
||||
|
||||
/*
|
||||
* 1. Enable GCC_PDM_AHB_CBCR clock for PDM block Access
|
||||
* 2. pwm_core_rate = clk_get_rate(pwm_core_clk); for now it is
|
||||
* 19.2MHz.
|
||||
* 3. min_freq = pwm_core_rate/2 ^ 16;
|
||||
* 4. max_freq = pwm_core_rate/2;
|
||||
* 5. calculate the frequency based on the period_ns and compare.
|
||||
*/
|
||||
ret = clk_prepare_enable(chip->pdm_ahb_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(chip->pwm_core_clk);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
mutex_lock(&chip->frames[hw_idx].frame_lock);
|
||||
|
||||
ret = __pdm_pwm_calc_pwm_frequency(chip, current_period, hw_idx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (chip->frames[hw_idx].current_period_ns != period_ns) {
|
||||
pr_err("Period cannot be updated, calculating dutycycle on old period\n");
|
||||
current_period = chip->frames[hw_idx].current_period_ns;
|
||||
}
|
||||
|
||||
ctl1 = DIV_ROUND_CLOSEST(chip->pwm_core_rate,
|
||||
chip->frames[hw_idx].current_freq);
|
||||
|
||||
ctl1 = DIV_ROUND_CLOSEST(ctl1 * (DIV_ROUND_CLOSEST((duty_ns * 100),
|
||||
current_period)), 100);
|
||||
|
||||
regmap_read(chip->regmap, chip->frames[hw_idx].reg_offset
|
||||
+ PWM_CYC_CFG, &cyc_cfg);
|
||||
if ((ctl1 > cyc_cfg || ctl1 <= 0) && duty_ns != 0) {
|
||||
pr_err("Duty cycle cannot be set at and beyond/below this limit\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(chip->regmap, chip->frames[hw_idx].reg_offset
|
||||
+ PWM_CTL2, GENMASK(15, 0), 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = regmap_update_bits(chip->regmap, chip->frames[hw_idx].reg_offset
|
||||
+ PWM_CTL1, GENMASK(15, 0), ctl1);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = regmap_update_bits(chip->regmap, chip->frames[hw_idx].reg_offset
|
||||
+ PWM_UPDATE, BIT(0), 1);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
chip->frames[hw_idx].current_duty_ns = duty_ns;
|
||||
out:
|
||||
mutex_unlock(&chip->frames[hw_idx].frame_lock);
|
||||
|
||||
clk_disable_unprepare(chip->pwm_core_clk);
|
||||
fail:
|
||||
clk_disable_unprepare(chip->pdm_ahb_clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pdm_pwm_free(struct pwm_chip *pwm_chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct pdm_pwm_chip *chip = container_of(pwm_chip,
|
||||
struct pdm_pwm_chip, pwm_chip);
|
||||
u32 hw_idx = pwm->hwpwm;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
chip->frames[hw_idx].freq_set = false;
|
||||
chip->frames[hw_idx].current_period_ns = 0;
|
||||
chip->frames[hw_idx].current_duty_ns = 0;
|
||||
|
||||
mutex_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static int pdm_pwm_enable(struct pdm_pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
u32 ret, val;
|
||||
u32 hw_idx = pwm->hwpwm;
|
||||
|
||||
ret = clk_prepare_enable(chip->pdm_ahb_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(chip->pwm_core_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(chip->pdm_ahb_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
/* Check the channel in Chip channel and enable the BIT in PWM_TOP */
|
||||
pr_debug("%s: PWM device Label %s, HW index %u, PWM index %u\n",
|
||||
__func__, pwm->label, hw_idx, pwm->pwm);
|
||||
pr_debug("%s: PWM frame-index %d, frame-offset 0x%x\n", __func__,
|
||||
chip->frames[hw_idx].frame_id,
|
||||
chip->frames[hw_idx].reg_offset);
|
||||
|
||||
val = BIT(chip->frames[hw_idx].frame_id);
|
||||
ret = regmap_update_bits(chip->regmap, PWM_TOPCTL0, val, val);
|
||||
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
chip->frames[hw_idx].is_enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdm_pwm_disable(struct pdm_pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
u32 val, hw_idx = pwm->hwpwm;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
/* Check the channel in the chip and disable the BIT in PWM_TOP */
|
||||
pr_debug("%s:PWM device Label %s\n", __func__, pwm->label);
|
||||
|
||||
val = BIT(chip->frames[hw_idx].frame_id);
|
||||
ret = regmap_update_bits(chip->regmap, PWM_TOPCTL0, val, 0);
|
||||
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
chip->frames[hw_idx].is_enabled = false;
|
||||
|
||||
clk_disable_unprepare(chip->pwm_core_clk);
|
||||
clk_disable_unprepare(chip->pdm_ahb_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdm_pwm_apply(struct pwm_chip *pwm_chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct pdm_pwm_chip *chip = container_of(pwm_chip,
|
||||
struct pdm_pwm_chip, pwm_chip);
|
||||
struct pwm_state curr_state;
|
||||
int ret;
|
||||
|
||||
pwm_get_state(pwm, &curr_state);
|
||||
|
||||
if (state->period < curr_state.period)
|
||||
return -EINVAL;
|
||||
|
||||
if (state->period != curr_state.period ||
|
||||
state->duty_cycle != curr_state.duty_cycle) {
|
||||
ret = pdm_pwm_config(chip, pwm->hwpwm, state->duty_cycle,
|
||||
state->period);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to update PWM configuration\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->enabled != curr_state.enabled) {
|
||||
if (state->enabled)
|
||||
return pdm_pwm_enable(chip, pwm);
|
||||
|
||||
ret = pdm_pwm_disable(chip, pwm);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwm_ops pdm_pwm_ops = {
|
||||
.apply = pdm_pwm_apply,
|
||||
.free = pdm_pwm_free,
|
||||
.get_state = pdm_pwm_get_state,
|
||||
};
|
||||
|
||||
static const struct regmap_config pwm_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int pdm_pwm_parse_dt(struct platform_device *pdev,
|
||||
struct pdm_pwm_chip *chip)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *frame_node;
|
||||
void __iomem *base;
|
||||
int count, ret;
|
||||
|
||||
chip->pdm_ahb_clk = devm_clk_get(chip->dev, "pdm_ahb_clk");
|
||||
if (IS_ERR(chip->pdm_ahb_clk)) {
|
||||
if (PTR_ERR(chip->pdm_ahb_clk) != -EPROBE_DEFER)
|
||||
dev_err(chip->dev, "Unable to get ahb clock handle\n");
|
||||
return PTR_ERR(chip->pdm_ahb_clk);
|
||||
}
|
||||
|
||||
chip->pwm_core_clk = devm_clk_get(chip->dev, "pwm_core_clk");
|
||||
if (IS_ERR(chip->pwm_core_clk)) {
|
||||
if (PTR_ERR(chip->pwm_core_clk) != -EPROBE_DEFER)
|
||||
dev_err(chip->dev, "Unable to get core clock handle\n");
|
||||
return PTR_ERR(chip->pwm_core_clk);
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(chip->dev, "Failed to get reg base resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
base = devm_ioremap(chip->dev, res->start, resource_size(res));
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->regmap = devm_regmap_init_mmio(chip->dev, base,
|
||||
&pwm_regmap_config);
|
||||
if (!chip->regmap) {
|
||||
dev_err(chip->dev, "Couldn't get regmap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!of_find_property(np, "assigned-clocks", NULL)) {
|
||||
dev_err(chip->dev, "missing parent clock handle\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!of_find_property(np, "assigned-clock-rates", NULL)) {
|
||||
dev_err(chip->dev, "missing parent clock rate\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip->pwm_core_rate = clk_get_rate(chip->pwm_core_clk);
|
||||
|
||||
chip->num_frames = of_get_child_count(np);
|
||||
if (!chip->num_frames ||
|
||||
chip->num_frames > chip->priv_data->max_channels) {
|
||||
dev_err(chip->dev, "PWM frames 0-%u are supported.\n",
|
||||
chip->priv_data->max_channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->frames = devm_kcalloc(chip->dev, chip->num_frames,
|
||||
sizeof(*chip->frames), GFP_KERNEL);
|
||||
if (!chip->frames)
|
||||
return -ENOMEM;
|
||||
|
||||
count = 0;
|
||||
for_each_available_child_of_node(np, frame_node) {
|
||||
u32 n, off;
|
||||
|
||||
if (of_property_read_u32(frame_node, "frame-index", &n)) {
|
||||
pr_err(FW_BUG "Missing frame-index.\n");
|
||||
of_node_put(frame_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
chip->frames[count].frame_id = n;
|
||||
|
||||
if (of_property_read_u32(frame_node, "frame-offset", &off)) {
|
||||
pr_err(FW_BUG "Missing frame-offset.\n");
|
||||
of_node_put(frame_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
chip->frames[count].reg_offset = off;
|
||||
|
||||
/* Holding a reference to the pdm chip for debug operations. */
|
||||
chip->frames[count].pwm_chip = chip;
|
||||
|
||||
mutex_init(&chip->frames[count].frame_lock);
|
||||
count++;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(chip->pdm_ahb_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(chip->regmap, PWM_TOPCTL0,
|
||||
GENMASK(chip->num_frames, 0), 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_disable_unprepare(chip->pdm_ahb_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static int duty_get(void *data, u64 *val)
|
||||
{
|
||||
struct pdm_pwm_frames *frame = data;
|
||||
|
||||
*val = DIV_ROUND_CLOSEST((frame->current_duty_ns * 100),
|
||||
frame->current_period_ns);
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(pwm_duty_fops, duty_get, NULL, "%lld\n");
|
||||
|
||||
static int enabled(void *data, u64 *val)
|
||||
{
|
||||
struct pdm_pwm_frames *frame = data;
|
||||
struct pdm_pwm_chip *chip = frame->pwm_chip;
|
||||
u32 temp, reg_offset;
|
||||
|
||||
*val = 0;
|
||||
reg_offset = chip->priv_data->status_reg_offsets[ENABLE_STATUS0];
|
||||
|
||||
if (chip->priv_data->status_reg_offsets[ENABLE_STATUS1] &&
|
||||
frame->frame_id > 10)
|
||||
reg_offset =
|
||||
chip->priv_data->status_reg_offsets[ENABLE_STATUS1];
|
||||
|
||||
regmap_read(chip->regmap, reg_offset, &temp);
|
||||
if (BIT((frame->frame_id % 10) + BIT(0)) & temp)
|
||||
*val = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(pwm_enable_fops, enabled, NULL, "%lld\n");
|
||||
|
||||
static int print_hw_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct pdm_pwm_frames *frame = m->private;
|
||||
u32 ctl1, ctl2, cyc_cfg, period_cnt;
|
||||
|
||||
regmap_read(frame->pwm_chip->regmap, frame->reg_offset + PWM_CTL1,
|
||||
&ctl1);
|
||||
regmap_read(frame->pwm_chip->regmap, frame->reg_offset + PWM_CTL2,
|
||||
&ctl2);
|
||||
regmap_read(frame->pwm_chip->regmap, frame->reg_offset + PWM_CYC_CFG,
|
||||
&cyc_cfg);
|
||||
regmap_read(frame->pwm_chip->regmap, frame->reg_offset + PWM_PERIOD_CNT,
|
||||
&period_cnt);
|
||||
|
||||
seq_printf(m, "PWM_CTL1 : 0x%x\nPWM_CTL2 : 0x%x\n", ctl1, ctl2);
|
||||
seq_printf(m, "PWM_CYC_CFG : 0x%x\nPWM_PERIOD_CNT : 0x%x\n", cyc_cfg,
|
||||
period_cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_hw_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, print_hw_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations pwm_list_regs_fops = {
|
||||
.open = print_hw_open,
|
||||
.read = seq_read,
|
||||
};
|
||||
|
||||
static int freq_get(void *data, u64 *val)
|
||||
{
|
||||
struct pdm_pwm_frames *frame = data;
|
||||
|
||||
*val = PERIOD_TO_HZ(frame->current_period_ns);
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(pwm_freq_fops, freq_get, NULL, "%lld\n");
|
||||
|
||||
static int period_ns_get(void *data, u64 *val)
|
||||
{
|
||||
struct pdm_pwm_frames *frame = data;
|
||||
|
||||
*val = frame->current_period_ns;
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(pwm_period_ns_fops, period_ns_get, NULL, "%lld\n");
|
||||
|
||||
static int duty_ns_get(void *data, u64 *val)
|
||||
{
|
||||
struct pdm_pwm_frames *frame = data;
|
||||
|
||||
*val = frame->current_duty_ns;
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(pwm_duty_ns_fops, duty_ns_get, NULL, "%lld\n");
|
||||
|
||||
static void pdm_dwm_debug_init(struct pwm_chip *pwm_chip)
|
||||
{
|
||||
struct pdm_pwm_chip *chip = container_of(pwm_chip,
|
||||
struct pdm_pwm_chip, pwm_chip);
|
||||
struct pwm_device *pwm;
|
||||
static struct dentry *debugfs_base, *debugfs_frame_base;
|
||||
int i, hw_idx;
|
||||
char frame[FRAME_NUM_MAX_LEN];
|
||||
|
||||
debugfs_base = debugfs_create_dir(chip->dev->of_node->name, NULL);
|
||||
if (IS_ERR_OR_NULL(debugfs_base)) {
|
||||
pr_err("Failed in creating debugfs directory.\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < pwm_chip->npwm; i++) {
|
||||
pwm = &pwm_chip->pwms[i];
|
||||
hw_idx = pwm->hwpwm;
|
||||
|
||||
snprintf(frame, FRAME_NUM_MAX_LEN, "frame_%d",
|
||||
chip->frames[hw_idx].frame_id);
|
||||
debugfs_frame_base = debugfs_create_dir(frame, debugfs_base);
|
||||
|
||||
debugfs_create_file("enabled", 0444, debugfs_frame_base,
|
||||
&chip->frames[hw_idx], &pwm_enable_fops);
|
||||
|
||||
debugfs_create_file("current_duty", 0444, debugfs_frame_base,
|
||||
&chip->frames[hw_idx], &pwm_duty_fops);
|
||||
|
||||
debugfs_create_file("pwm_print_regs", 0444, debugfs_frame_base,
|
||||
&chip->frames[hw_idx], &pwm_list_regs_fops);
|
||||
|
||||
debugfs_create_file("current_frequency_hz", 0444,
|
||||
debugfs_frame_base,
|
||||
&chip->frames[hw_idx], &pwm_freq_fops);
|
||||
|
||||
debugfs_create_file("current_period_ns", 0444,
|
||||
debugfs_frame_base,
|
||||
&chip->frames[hw_idx], &pwm_period_ns_fops);
|
||||
|
||||
debugfs_create_file("current_duty_cycle_ns", 0444,
|
||||
debugfs_frame_base,
|
||||
&chip->frames[hw_idx], &pwm_duty_ns_fops);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int pdm_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pdm_pwm_chip *chip;
|
||||
int rc;
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->priv_data = (struct pdm_pwm_priv_data *)
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
if (IS_ERR_OR_NULL(chip->priv_data))
|
||||
return -EINVAL;
|
||||
|
||||
chip->dev = &pdev->dev;
|
||||
mutex_init(&chip->lock);
|
||||
rc = pdm_pwm_parse_dt(pdev, chip);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Devicetree properties parsing failed, rc=%d\n", rc);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
dev_set_drvdata(chip->dev, chip);
|
||||
chip->pwm_chip.dev = chip->dev;
|
||||
chip->pwm_chip.base = -1;
|
||||
chip->pwm_chip.npwm = chip->num_frames;
|
||||
chip->pwm_chip.ops = &pdm_pwm_ops;
|
||||
|
||||
rc = pwmchip_add(&chip->pwm_chip);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Add pwmchip failed, rc=%d\n", rc);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
pdm_dwm_debug_init(&chip->pwm_chip);
|
||||
#endif
|
||||
dev_info(chip->dev, "pwmchip driver success.\n");
|
||||
return rc;
|
||||
err_out:
|
||||
mutex_destroy(&chip->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pdm_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pdm_pwm_chip *chip = dev_get_drvdata(&pdev->dev);
|
||||
int rc;
|
||||
|
||||
rc = pwmchip_remove(&chip->pwm_chip);
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "Remove pwmchip failed, rc=%d\n", rc);
|
||||
|
||||
mutex_destroy(&chip->lock);
|
||||
|
||||
dev_set_drvdata(chip->dev, NULL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct pdm_pwm_priv_data pdm_pwm_reg_offsets = {
|
||||
.max_channels = 10,
|
||||
.status_reg_offsets = (u16 [ENABLE_STATUS_REG_SIZE]) {
|
||||
[ENABLE_STATUS0] = 0xc,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id pdm_pwm_of_match[] = {
|
||||
{ .compatible = "qcom,pdm-pwm", .data = &pdm_pwm_reg_offsets },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver pdm_pwm_driver = {
|
||||
.driver = {
|
||||
.name = "pdm-pwm",
|
||||
.of_match_table = pdm_pwm_of_match,
|
||||
},
|
||||
.probe = pdm_pwm_probe,
|
||||
.remove = pdm_pwm_remove,
|
||||
};
|
||||
module_platform_driver(pdm_pwm_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QTI PDM PWM driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("pwm:pdm-pwm");
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2009-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
@ -209,6 +210,14 @@ struct socinfo_v0_15 {
|
|||
uint32_t nmodem_supported;
|
||||
};
|
||||
|
||||
struct socinfo_v0_16 {
|
||||
struct socinfo_v0_15 v0_15;
|
||||
__le32 feature_code;
|
||||
__le32 pcode;
|
||||
__le32 npartnamemap_offset;
|
||||
__le32 nnum_partname_mapping;
|
||||
};
|
||||
|
||||
static union {
|
||||
struct socinfo_v0_1 v0_1;
|
||||
struct socinfo_v0_2 v0_2;
|
||||
|
@ -225,10 +234,43 @@ static union {
|
|||
struct socinfo_v0_13 v0_13;
|
||||
struct socinfo_v0_14 v0_14;
|
||||
struct socinfo_v0_15 v0_15;
|
||||
struct socinfo_v0_16 v0_16;
|
||||
} *socinfo;
|
||||
|
||||
#define PART_NAME_MAX 32
|
||||
struct socinfo_partinfo {
|
||||
__le32 part_type;
|
||||
char part_name[PART_NAME_MAX];
|
||||
__le32 part_name_len;
|
||||
};
|
||||
struct socinfo_partinfo partinfo[SOCINFO_PART_MAX_PARTTYPE];
|
||||
|
||||
/* max socinfo format version supported */
|
||||
#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 15)
|
||||
#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 16)
|
||||
|
||||
static const char * const hw_platform_feature_code[] = {
|
||||
[SOCINFO_FC_UNKNOWN] = "Unknown",
|
||||
[SOCINFO_FC_AA] = "AA",
|
||||
[SOCINFO_FC_AB] = "AB",
|
||||
[SOCINFO_FC_AC] = "AC",
|
||||
[SOCINFO_FC_AD] = "AD",
|
||||
[SOCINFO_FC_AE] = "AE",
|
||||
[SOCINFO_FC_AF] = "AF",
|
||||
[SOCINFO_FC_AG] = "AG",
|
||||
[SOCINFO_FC_AH] = "AH",
|
||||
};
|
||||
|
||||
#define SOCINFO_FC_INT_MASK 0x0f
|
||||
static const char * const hw_platform_ifeature_code[] = {
|
||||
[SOCINFO_FC_Y0 - SOCINFO_FC_Y0] = "Y0",
|
||||
[SOCINFO_FC_Y1 - SOCINFO_FC_Y0] = "Y1",
|
||||
[SOCINFO_FC_Y2 - SOCINFO_FC_Y0] = "Y2",
|
||||
[SOCINFO_FC_Y3 - SOCINFO_FC_Y0] = "Y3",
|
||||
[SOCINFO_FC_Y4 - SOCINFO_FC_Y0] = "Y4",
|
||||
[SOCINFO_FC_Y5 - SOCINFO_FC_Y0] = "Y5",
|
||||
[SOCINFO_FC_Y6 - SOCINFO_FC_Y0] = "Y6",
|
||||
[SOCINFO_FC_Y7 - SOCINFO_FC_Y0] = "Y7",
|
||||
};
|
||||
|
||||
static struct msm_soc_info cpu_of_id[] = {
|
||||
[0] = {MSM_CPU_UNKNOWN, "Unknown CPU"},
|
||||
|
@ -408,6 +450,7 @@ static struct msm_soc_info cpu_of_id[] = {
|
|||
static enum msm_cpu cur_cpu;
|
||||
static int current_image;
|
||||
static uint32_t socinfo_format;
|
||||
static const char *sku;
|
||||
|
||||
static struct socinfo_v0_1 dummy_socinfo = {
|
||||
.format = SOCINFO_VERSION(0, 1),
|
||||
|
@ -657,6 +700,117 @@ static uint32_t socinfo_get_nmodem_supported(void)
|
|||
: 0;
|
||||
}
|
||||
|
||||
static uint32_t socinfo_get_feature_code_id(void)
|
||||
{
|
||||
uint32_t fc_id;
|
||||
|
||||
if (!socinfo || socinfo_format < SOCINFO_VERSION(0, 16))
|
||||
return SOCINFO_FC_UNKNOWN;
|
||||
|
||||
fc_id = le32_to_cpu(socinfo->v0_16.feature_code);
|
||||
if (fc_id <= SOCINFO_FC_UNKNOWN || fc_id >= SOCINFO_FC_INT_RESERVE)
|
||||
return SOCINFO_FC_UNKNOWN;
|
||||
|
||||
return fc_id;
|
||||
}
|
||||
|
||||
static const char *socinfo_get_feature_code_mapping(void)
|
||||
{
|
||||
uint32_t id = socinfo_get_feature_code_id();
|
||||
|
||||
if (id > SOCINFO_FC_UNKNOWN && id < SOCINFO_FC_EXT_RESERVE)
|
||||
return hw_platform_feature_code[id];
|
||||
else if (id >= SOCINFO_FC_Y0 && id < SOCINFO_FC_INT_RESERVE)
|
||||
return hw_platform_ifeature_code[id & SOCINFO_FC_INT_MASK];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t socinfo_get_pcode_id(void)
|
||||
{
|
||||
uint32_t pcode;
|
||||
|
||||
if (!socinfo || socinfo_format < SOCINFO_VERSION(0, 16))
|
||||
return SOCINFO_PCODE_RESERVE;
|
||||
|
||||
pcode = le32_to_cpu(socinfo->v0_16.pcode);
|
||||
if (pcode <= SOCINFO_PCODE_UNKNOWN || pcode >= SOCINFO_PCODE_RESERVE)
|
||||
return SOCINFO_PCODE_UNKNOWN;
|
||||
|
||||
return pcode;
|
||||
}
|
||||
|
||||
int socinfo_get_feature_code(void)
|
||||
{
|
||||
if (socinfo_format < SOCINFO_VERSION(0, 16)) {
|
||||
pr_warn("socinfo: Feature code is not supported by bootloaders\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return socinfo_get_feature_code_id();
|
||||
}
|
||||
EXPORT_SYMBOL(socinfo_get_feature_code);
|
||||
|
||||
int socinfo_get_pcode(void)
|
||||
{
|
||||
if (socinfo_format < SOCINFO_VERSION(0, 16)) {
|
||||
pr_warn("socinfo: pcode is not supported by bootloaders\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return socinfo_get_pcode_id();
|
||||
}
|
||||
EXPORT_SYMBOL(socinfo_get_pcode);
|
||||
|
||||
char *socinfo_get_partinfo_details(unsigned int part_id)
|
||||
{
|
||||
if (socinfo_format < SOCINFO_VERSION(0, 16) ||
|
||||
part_id > SOCINFO_PART_MAX_PARTTYPE)
|
||||
return NULL;
|
||||
|
||||
return partinfo[part_id].part_name;
|
||||
}
|
||||
EXPORT_SYMBOL(socinfo_get_partinfo_details);
|
||||
|
||||
void socinfo_enumerate_partinfo_details(void)
|
||||
{
|
||||
unsigned int partinfo_array_offset;
|
||||
unsigned int nnum_partname_mapping;
|
||||
void *ptr = socinfo;
|
||||
int i, part_type, part_name_len;
|
||||
|
||||
if (socinfo_format < SOCINFO_VERSION(0, 16))
|
||||
return;
|
||||
|
||||
partinfo_array_offset =
|
||||
le32_to_cpu(socinfo->v0_16.npartnamemap_offset);
|
||||
nnum_partname_mapping =
|
||||
le32_to_cpu(socinfo->v0_16.nnum_partname_mapping);
|
||||
|
||||
if (nnum_partname_mapping > SOCINFO_PART_MAX_PARTTYPE) {
|
||||
pr_warn("socinfo: Mismatch between bootloaders and hlos\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptr += partinfo_array_offset;
|
||||
for (i = 0; i < nnum_partname_mapping; i++) {
|
||||
part_type = get_unaligned_le32(ptr);
|
||||
if (part_type > SOCINFO_PART_MAX_PARTTYPE)
|
||||
pr_warn("socinfo: part type mismatch\n");
|
||||
|
||||
partinfo[part_type].part_type = part_type;
|
||||
ptr += sizeof(u32);
|
||||
strscpy(partinfo[part_type].part_name, ptr, PART_NAME_MAX);
|
||||
part_name_len = strlen(partinfo[part_type].part_name);
|
||||
ptr += PART_NAME_MAX;
|
||||
if (part_name_len != get_unaligned_le32(ptr))
|
||||
pr_warn("socinfo: part info string length mismatch\n");
|
||||
|
||||
partinfo[part_type].part_name_len = part_name_len;
|
||||
ptr += sizeof(u32);
|
||||
}
|
||||
}
|
||||
|
||||
enum pmic_model socinfo_get_pmic_model(void)
|
||||
{
|
||||
return socinfo ?
|
||||
|
@ -988,6 +1142,34 @@ msm_get_nmodem_supported(struct device *dev,
|
|||
socinfo_get_nmodem_supported());
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
msm_get_sku(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n",
|
||||
sku ? sku : "Unknown");
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
msm_get_pcode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "0x%x\n", socinfo_get_pcode_id());
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
msm_get_feature_code(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
const char *feature_code = socinfo_get_feature_code_mapping();
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n",
|
||||
feature_code ? feature_code : "Unknown");
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
msm_get_pmic_model(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
|
@ -1303,6 +1485,15 @@ static struct device_attribute msm_soc_attr_nmodem_supported =
|
|||
__ATTR(nmodem_supported, 0444,
|
||||
msm_get_nmodem_supported, NULL);
|
||||
|
||||
static struct device_attribute msm_soc_attr_sku =
|
||||
__ATTR(sku, 0444, msm_get_sku, NULL);
|
||||
|
||||
static struct device_attribute msm_soc_attr_feature_code =
|
||||
__ATTR(feature_code, 0444, msm_get_feature_code, NULL);
|
||||
|
||||
static struct device_attribute msm_soc_attr_pcode =
|
||||
__ATTR(pcode, 0444, msm_get_pcode, NULL);
|
||||
|
||||
static struct device_attribute msm_soc_attr_pmic_model =
|
||||
__ATTR(pmic_model, 0444,
|
||||
msm_get_pmic_model, NULL);
|
||||
|
@ -1489,6 +1680,13 @@ static void __init populate_soc_sysfs_files(struct device *msm_soc_device)
|
|||
device_create_file(msm_soc_device, &images);
|
||||
|
||||
switch (socinfo_format) {
|
||||
case SOCINFO_VERSION(0, 16):
|
||||
device_create_file(msm_soc_device,
|
||||
&msm_soc_attr_sku);
|
||||
device_create_file(msm_soc_device,
|
||||
&msm_soc_attr_feature_code);
|
||||
device_create_file(msm_soc_device,
|
||||
&msm_soc_attr_pcode);
|
||||
case SOCINFO_VERSION(0, 15):
|
||||
device_create_file(msm_soc_device,
|
||||
&msm_soc_attr_nmodem_supported);
|
||||
|
@ -1787,6 +1985,33 @@ static void socinfo_print(void)
|
|||
socinfo->v0_15.nmodem_supported);
|
||||
break;
|
||||
|
||||
case SOCINFO_VERSION(0, 16):
|
||||
pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u serial_number=%u num_pmics=%u chip_family=0x%x raw_device_family=0x%x raw_device_number=0x%x nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_subset_parts=0x%x nsubset_parts_array_offset=0x%x nmodem_supported=0x%x feature_code=0x%x pcode=0x%x sku=%s\n",
|
||||
f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
|
||||
socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
|
||||
socinfo->v0_3.hw_platform,
|
||||
socinfo->v0_4.platform_version,
|
||||
socinfo->v0_5.accessory_chip,
|
||||
socinfo->v0_6.hw_platform_subtype,
|
||||
socinfo->v0_7.pmic_model,
|
||||
socinfo->v0_7.pmic_die_revision,
|
||||
socinfo->v0_9.foundry_id,
|
||||
socinfo->v0_10.serial_number,
|
||||
socinfo->v0_11.num_pmics,
|
||||
socinfo->v0_12.chip_family,
|
||||
socinfo->v0_12.raw_device_family,
|
||||
socinfo->v0_12.raw_device_number,
|
||||
socinfo->v0_13.nproduct_id,
|
||||
socinfo->v0_14.num_clusters,
|
||||
socinfo->v0_14.ncluster_array_offset,
|
||||
socinfo->v0_14.num_subset_parts,
|
||||
socinfo->v0_14.nsubset_parts_array_offset,
|
||||
socinfo->v0_15.nmodem_supported,
|
||||
socinfo->v0_16.feature_code,
|
||||
socinfo->v0_16.pcode,
|
||||
sku ? sku : "Unknown");
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("Unknown format found: v%u.%u\n", f_maj, f_min);
|
||||
break;
|
||||
|
@ -1819,6 +2044,7 @@ int __init socinfo_init(void)
|
|||
static bool socinfo_init_done;
|
||||
size_t size;
|
||||
uint32_t soc_info_id;
|
||||
const char *machine, *fc;
|
||||
|
||||
if (socinfo_init_done)
|
||||
return 0;
|
||||
|
@ -1838,6 +2064,14 @@ int __init socinfo_init(void)
|
|||
(!cpu_of_id[soc_info_id].soc_id_string))
|
||||
pr_warn("New IDs added! ID => CPU mapping needs an update.\n");
|
||||
|
||||
if (socinfo_format >= SOCINFO_VERSION(0, 16)) {
|
||||
socinfo_enumerate_partinfo_details();
|
||||
machine = socinfo_get_id_string();
|
||||
fc = socinfo_get_feature_code_mapping();
|
||||
sku = kasprintf(GFP_KERNEL, "%s-%u-%s",
|
||||
machine, socinfo_get_pcode(), fc);
|
||||
}
|
||||
|
||||
cur_cpu = cpu_of_id[socinfo->v0_1.id].generic_soc_type;
|
||||
boot_stats_init();
|
||||
socinfo_print();
|
||||
|
|
|
@ -4868,7 +4868,7 @@ struct mdss_panel_cfg *mdss_panel_intf_type(int intf_val)
|
|||
}
|
||||
EXPORT_SYMBOL(mdss_panel_intf_type);
|
||||
|
||||
struct irq_info *mdss_intr_line()
|
||||
struct irq_info *mdss_intr_line(void)
|
||||
{
|
||||
return mdss_mdp_hw.irq_info;
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ struct mdss_util_intf mdss_util = {
|
|||
.mdp_probe_done = false
|
||||
};
|
||||
|
||||
struct mdss_util_intf *mdss_get_util_intf()
|
||||
struct mdss_util_intf *mdss_get_util_intf(void)
|
||||
{
|
||||
return &mdss_util;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SCUBA_H
|
||||
|
@ -155,6 +156,7 @@
|
|||
#define GCC_VIDEO_VENUS_CLK_SRC 145
|
||||
#define GCC_VIDEO_VENUS_CTL_CLK 146
|
||||
#define GCC_VIDEO_XO_CLK 147
|
||||
#define GCC_PWM0_XO512_DIV_CLK_SRC 148
|
||||
|
||||
/* GCC resets */
|
||||
#define GCC_CAMSS_OPE_BCR 0
|
||||
|
|
|
@ -1704,7 +1704,12 @@ void sk_common_release(struct sock *sk);
|
|||
* Default socket callbacks and setup code
|
||||
*/
|
||||
|
||||
/* Initialise core socket variables */
|
||||
/* Initialise core socket variables using an explicit uid. */
|
||||
void sock_init_data_uid(struct socket *sock, struct sock *sk, kuid_t uid);
|
||||
|
||||
/* Initialise core socket variables
|
||||
* Assumes struct socket *sock is embedded in a struct socket_alloc.
|
||||
*/
|
||||
void sock_init_data(struct socket *sock, struct sock *sk);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2009-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ARCH_ARM_MACH_MSM_SOCINFO_H_
|
||||
|
@ -13,6 +14,64 @@
|
|||
#include <linux/of.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
|
||||
enum feature_code {
|
||||
/* External feature code */
|
||||
SOCINFO_FC_UNKNOWN = 0x0,
|
||||
SOCINFO_FC_AA,
|
||||
SOCINFO_FC_AB,
|
||||
SOCINFO_FC_AC,
|
||||
SOCINFO_FC_AD,
|
||||
SOCINFO_FC_AE,
|
||||
SOCINFO_FC_AF,
|
||||
SOCINFO_FC_AG,
|
||||
SOCINFO_FC_AH,
|
||||
SOCINFO_FC_EXT_RESERVE,
|
||||
|
||||
/* Internal feature code */
|
||||
SOCINFO_FC_Y0 = 0xf1,
|
||||
SOCINFO_FC_Y1,
|
||||
SOCINFO_FC_Y2,
|
||||
SOCINFO_FC_Y3,
|
||||
SOCINFO_FC_Y4,
|
||||
SOCINFO_FC_Y5,
|
||||
SOCINFO_FC_Y6,
|
||||
SOCINFO_FC_Y7,
|
||||
SOCINFO_FC_INT_RESERVE
|
||||
};
|
||||
|
||||
enum pcode {
|
||||
SOCINFO_PCODE_UNKNOWN = 0,
|
||||
SOCINFO_PCODE_0,
|
||||
SOCINFO_PCODE_1,
|
||||
SOCINFO_PCODE_2,
|
||||
SOCINFO_PCODE_3,
|
||||
SOCINFO_PCODE_4,
|
||||
SOCINFO_PCODE_5,
|
||||
SOCINFO_PCODE_6,
|
||||
SOCINFO_PCODE_7,
|
||||
SOCINFO_PCODE_8,
|
||||
SOCINFO_PCODE_RESERVE = 0x7fffffff
|
||||
};
|
||||
|
||||
enum socinfo_parttype {
|
||||
SOCINFO_PART_GPU,
|
||||
SOCINFO_PART_VIDEO,
|
||||
SOCINFO_PART_CAMERA,
|
||||
SOCINFO_PART_DISPLAY,
|
||||
SOCINFO_PART_AUDIO,
|
||||
SOCINFO_PART_MODEM,
|
||||
SOCINFO_PART_WLAN,
|
||||
SOCINFO_PART_COMP,
|
||||
SOCINFO_PART_SENSORS,
|
||||
SOCINFO_PART_NPU,
|
||||
SOCINFO_PART_SPSS,
|
||||
SOCINFO_PART_NAV,
|
||||
SOCINFO_PART_COMPUTE_1,
|
||||
SOCINFO_PART_DISPLAY_1,
|
||||
SOCINFO_PART_MAX_PARTTYPE
|
||||
};
|
||||
|
||||
/*
|
||||
* SOC version type with major number in the upper 16 bits and minor
|
||||
* number in the lower 16 bits. For example:
|
||||
|
@ -272,5 +331,8 @@ bool socinfo_get_part_info(enum subset_part_type part);
|
|||
enum pmic_model socinfo_get_pmic_model(void);
|
||||
uint32_t socinfo_get_pmic_die_revision(void);
|
||||
int __init socinfo_init(void) __must_check;
|
||||
int socinfo_get_feature_code(void);
|
||||
int socinfo_get_pcode(void);
|
||||
char *socinfo_get_partinfo_details(unsigned int part_id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -104,14 +104,34 @@ fixup_cumulative_runnable_avg(struct walt_sched_stats *stats,
|
|||
s64 demand_scaled_delta,
|
||||
s64 pred_demand_scaled_delta)
|
||||
{
|
||||
s64 cumulative_runnable_avg_scaled;
|
||||
s64 pred_demands_sum_scaled;
|
||||
|
||||
if (sched_disable_window_stats)
|
||||
return;
|
||||
|
||||
stats->cumulative_runnable_avg_scaled += demand_scaled_delta;
|
||||
BUG_ON((s64)stats->cumulative_runnable_avg_scaled < 0);
|
||||
cumulative_runnable_avg_scaled =
|
||||
(s64)stats->cumulative_runnable_avg_scaled +
|
||||
demand_scaled_delta;
|
||||
pred_demands_sum_scaled =
|
||||
(s64)stats->pred_demands_sum_scaled + pred_demand_scaled_delta;
|
||||
|
||||
stats->pred_demands_sum_scaled += pred_demand_scaled_delta;
|
||||
BUG_ON((s64)stats->pred_demands_sum_scaled < 0);
|
||||
if (cumulative_runnable_avg_scaled < 0) {
|
||||
printk_deferred("WALT-BUG demand_scaled_delta=%lld cumulative_runnable_avg_scaled=%llu\n",
|
||||
demand_scaled_delta,
|
||||
stats->cumulative_runnable_avg_scaled);
|
||||
cumulative_runnable_avg_scaled = 0;
|
||||
}
|
||||
stats->cumulative_runnable_avg_scaled =
|
||||
(u64)cumulative_runnable_avg_scaled;
|
||||
|
||||
if (pred_demands_sum_scaled < 0) {
|
||||
printk_deferred("WALT-BUG task pred_demand_scaled_delta=%lld pred_demands_sum_scaled=%llu\n",
|
||||
pred_demand_scaled_delta,
|
||||
stats->pred_demands_sum_scaled);
|
||||
pred_demands_sum_scaled = 0;
|
||||
}
|
||||
stats->pred_demands_sum_scaled = (u64)pred_demands_sum_scaled;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
|
@ -2792,7 +2792,7 @@ void sk_stop_timer(struct sock *sk, struct timer_list* timer)
|
|||
}
|
||||
EXPORT_SYMBOL(sk_stop_timer);
|
||||
|
||||
void sock_init_data(struct socket *sock, struct sock *sk)
|
||||
void sock_init_data_uid(struct socket *sock, struct sock *sk, kuid_t uid)
|
||||
{
|
||||
sk_init_common(sk);
|
||||
sk->sk_send_head = NULL;
|
||||
|
@ -2811,11 +2811,10 @@ void sock_init_data(struct socket *sock, struct sock *sk)
|
|||
sk->sk_type = sock->type;
|
||||
sk->sk_wq = sock->wq;
|
||||
sock->sk = sk;
|
||||
sk->sk_uid = SOCK_INODE(sock)->i_uid;
|
||||
} else {
|
||||
sk->sk_wq = NULL;
|
||||
sk->sk_uid = make_kuid(sock_net(sk)->user_ns, 0);
|
||||
}
|
||||
sk->sk_uid = uid;
|
||||
|
||||
rwlock_init(&sk->sk_callback_lock);
|
||||
if (sk->sk_kern_sock)
|
||||
|
@ -2873,6 +2872,16 @@ void sock_init_data(struct socket *sock, struct sock *sk)
|
|||
refcount_set(&sk->sk_refcnt, 1);
|
||||
atomic_set(&sk->sk_drops, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(sock_init_data_uid);
|
||||
|
||||
void sock_init_data(struct socket *sock, struct sock *sk)
|
||||
{
|
||||
kuid_t uid = sock ?
|
||||
SOCK_INODE(sock)->i_uid :
|
||||
make_kuid(sock_net(sk)->user_ns, 0);
|
||||
|
||||
sock_init_data_uid(sock, sk, uid);
|
||||
}
|
||||
EXPORT_SYMBOL(sock_init_data);
|
||||
|
||||
void lock_sock_nested(struct sock *sk, int subclass)
|
||||
|
|
Loading…
Reference in a new issue