diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 54df844831a8..765ac59c86ca 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -648,3 +648,12 @@ config SC_DEBUGCC_SHRIKE clock measurement functionality. endif + +config VIRTIO_CLK + tristate "Virtio clock driver" + depends on VIRTIO + help + This is the virtual clock driver for virtio. It can be used on + Qualcomm Technologies, Inc automotive virtual machine. + Say Y if you want to use pass through peripheral devices such as UART, + SPI, I2C, USB etc. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index ea7ddc9a5a0b..60e51e39e7f4 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -95,3 +95,4 @@ obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o obj-$(CONFIG_QCOM_HFPLL) += hfpll.o obj-$(CONFIG_KRAITCC) += krait-cc.o +obj-$(CONFIG_VIRTIO_CLK) += virtio_clk.o virtio_clk_sm8150.o virtio_clk_sm6150.o virtio_clk_sa8195p.o diff --git a/drivers/clk/qcom/virtio_clk.c b/drivers/clk/qcom/virtio_clk.c new file mode 100644 index 000000000000..c40208df7f91 --- /dev/null +++ b/drivers/clk/qcom/virtio_clk.c @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "virtio_clk_common.h" + +struct virtio_clk { + struct virtio_device *vdev; + struct virtqueue *vq; + struct completion rsp_avail; + struct mutex lock; + struct reset_controller_dev rcdev; + const struct clk_virtio_desc *desc; + struct clk_virtio *clks; + size_t num_clks; + size_t num_resets; +}; + +#define to_clk_virtio(_hw) container_of(_hw, struct clk_virtio, hw) + +struct clk_virtio { + int clk_id; + struct clk_hw hw; + struct virtio_clk *vclk; +}; + +struct virtio_cc_map { + char cc_name[20]; + const struct clk_virtio_desc *desc; +}; + +static int virtio_clk_prepare(struct clk_hw *hw) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_ENABLE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + wait_for_completion(&vclk->rsp_avail); + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vclk->vdev, rsp->result); +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static void virtio_clk_unprepare(struct clk_hw *hw) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_DISABLE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + wait_for_completion(&vclk->rsp_avail); + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + goto out; + } + + if (rsp->result) + pr_err("%s: error response (%d)\n", clk_hw_get_name(hw), + rsp->result); + +out: + mutex_unlock(&vclk->lock); + kfree(req); +} + +static int virtio_clk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_SET_RATE); + req->data[0] = cpu_to_virtio32(vclk->vdev, rate); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + wait_for_completion(&vclk->rsp_avail); + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vclk->vdev, rsp->result); +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static long virtio_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return 0; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_ROUND_RATE); + req->data[0] = cpu_to_virtio32(vclk->vdev, rate); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + wait_for_completion(&vclk->rsp_avail); + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = 0; + goto out; + } + + if (rsp->result) { + pr_err("%s: error response (%d)\n", clk_hw_get_name(hw), + rsp->result); + ret = 0; + } else + ret = virtio32_to_cpu(vclk->vdev, rsp->data[0]); + +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static unsigned long virtio_clk_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_virtio *v = to_clk_virtio(hw); + struct virtio_clk *vclk = v->vclk; + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return 0; + + strlcpy(req->name, clk_hw_get_name(hw), sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, v->clk_id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_GET_RATE); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("%s: fail to add output buffer (%d)\n", + clk_hw_get_name(hw), ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + wait_for_completion(&vclk->rsp_avail); + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("%s: fail to get virtqueue buffer\n", + clk_hw_get_name(hw)); + ret = 0; + goto out; + } + + if (rsp->result) { + pr_err("%s: error response (%d)\n", clk_hw_get_name(hw), + rsp->result); + ret = 0; + } else + ret = virtio32_to_cpu(vclk->vdev, rsp->data[0]); + +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static const struct clk_ops clk_virtio_ops = { + .prepare = virtio_clk_prepare, + .unprepare = virtio_clk_unprepare, + .set_rate = virtio_clk_set_rate, + .round_rate = virtio_clk_round_rate, + .recalc_rate = virtio_clk_get_rate, +}; + +static int +__virtio_reset(struct reset_controller_dev *rcdev, unsigned long id, + unsigned int action) +{ + struct virtio_clk *vclk = container_of(rcdev, struct virtio_clk, rcdev); + struct virtio_clk_msg *req, *rsp; + struct scatterlist sg[1]; + unsigned int len; + int ret = 0; + + req = kzalloc(sizeof(struct virtio_clk_msg), GFP_KERNEL); + if (!req) + return -ENOMEM; + + if (vclk->desc && vclk->desc->reset_names[id]) + strlcpy(req->name, vclk->desc->reset_names[id], + sizeof(req->name)); + req->id = cpu_to_virtio32(vclk->vdev, id); + req->type = cpu_to_virtio32(vclk->vdev, VIRTIO_CLK_T_RESET); + req->data[0] = cpu_to_virtio32(vclk->vdev, action); + sg_init_one(sg, req, sizeof(*req)); + + mutex_lock(&vclk->lock); + + ret = virtqueue_add_outbuf(vclk->vq, sg, 1, req, GFP_KERNEL); + if (ret) { + pr_err("fail to add output buffer (%d)\n", ret); + goto out; + } + + virtqueue_kick(vclk->vq); + + wait_for_completion(&vclk->rsp_avail); + + rsp = virtqueue_get_buf(vclk->vq, &len); + if (!rsp) { + pr_err("fail to get virtqueue buffer\n"); + ret = -EIO; + goto out; + } + + ret = virtio32_to_cpu(vclk->vdev, rsp->result); + +out: + mutex_unlock(&vclk->lock); + kfree(req); + + return ret; +} + +static int +virtio_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + return __virtio_reset(rcdev, id, 1); +} + +static int +virtio_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + return __virtio_reset(rcdev, id, 0); +} + +static int +virtio_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + rcdev->ops->assert(rcdev, id); + udelay(1); + rcdev->ops->deassert(rcdev, id); + return 0; +} + +static const struct reset_control_ops virtio_reset_ops = { + .reset = virtio_reset, + .assert = virtio_reset_assert, + .deassert = virtio_reset_deassert, +}; + +static void virtclk_isr(struct virtqueue *vq) +{ + struct virtio_clk *vclk = vq->vdev->priv; + + complete(&vclk->rsp_avail); +} + +static int virtclk_init_vqs(struct virtio_clk *vclk) +{ + struct virtqueue *vqs[1]; + vq_callback_t *cbs[] = { virtclk_isr }; + static const char * const names[] = { "clock" }; + int ret; + + ret = virtio_find_vqs(vclk->vdev, 1, vqs, cbs, names, NULL); + if (ret) + return ret; + + vclk->vq = vqs[0]; + + return 0; +} + +static const struct virtio_cc_map clk_virtio_map_table[] = { + { .cc_name = "sm8150-gcc", .desc = &clk_virtio_sm8150_gcc, }, + { .cc_name = "sm8150-scc", .desc = &clk_virtio_sm8150_scc, }, + { .cc_name = "sm6150-gcc", .desc = &clk_virtio_sm6150_gcc, }, + { .cc_name = "sm6150-scc", .desc = &clk_virtio_sm6150_scc, }, + { .cc_name = "sa8195p-gcc", .desc = &clk_virtio_sa8195p_gcc, }, + { } +}; + +static const struct clk_virtio_desc *virtclk_find_desc( + const struct virtio_cc_map *maps, + const char *name) +{ + if (!maps) + return NULL; + + for (; maps->cc_name[0]; maps++) { + if (!strcmp(name, maps->cc_name)) + return maps->desc; + } + + return NULL; +} + +static struct clk_hw * +of_clk_hw_virtio_get(struct of_phandle_args *clkspec, void *data) +{ + struct virtio_clk *vclk = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= vclk->num_clks) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &vclk->clks[idx].hw; +} + +static int virtio_clk_probe(struct virtio_device *vdev) +{ + const struct clk_virtio_desc *desc = NULL; + struct virtio_clk *vclk; + struct virtio_clk_config config; + struct clk_virtio *virtio_clks; + char name[40]; + struct clk_init_data init; + static int instance; + unsigned int i; + int ret; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + vclk = devm_kzalloc(&vdev->dev, sizeof(*vclk), GFP_KERNEL); + if (!vclk) + return -ENOMEM; + + vdev->priv = vclk; + vclk->vdev = vdev; + mutex_init(&vclk->lock); + init_completion(&vclk->rsp_avail); + + ret = virtclk_init_vqs(vclk); + if (ret) { + dev_err(&vdev->dev, "failed to initialized virtqueue\n"); + return ret; + } + + virtio_device_ready(vdev); + + memset(&config, 0x0, sizeof(config)); + + virtio_cread(vdev, struct virtio_clk_config, num_clks, + &config.num_clks); + virtio_cread_feature(vdev, VIRTIO_CLK_F_RESET, struct virtio_clk_config, + num_resets, &config.num_resets); + + if (virtio_has_feature(vdev, VIRTIO_CLK_F_NAME)) { + virtio_cread_bytes(vdev, + offsetof(struct virtio_clk_config, name), + &config.name, sizeof(config.name)); + desc = virtclk_find_desc(clk_virtio_map_table, config.name); + if (!desc) { + ret = -ENXIO; + goto err_find_desc; + } + } + + dev_dbg(&vdev->dev, "num_clks=%d, num_resets=%d, name=%s\n", + config.num_clks, config.num_resets, config.name); + + if (desc) { + vclk->desc = desc; + vclk->num_clks = desc->num_clks; + if (desc->num_resets > 0) + vclk->num_resets = desc->num_resets; + } else { + vclk->num_clks = config.num_clks; + if (config.num_resets > 0) + vclk->num_resets = config.num_resets; + } + + virtio_clks = devm_kcalloc(&vdev->dev, vclk->num_clks, + sizeof(struct clk_virtio), GFP_KERNEL); + if (!virtio_clks) { + ret = -ENOMEM; + goto err_kcalloc; + } + + vclk->clks = virtio_clks; + + memset(&init, 0x0, sizeof(init)); + init.ops = &clk_virtio_ops; + + if (desc) { + for (i = 0; i < vclk->num_clks; i++) { + if (!desc->clk_names[i]) + continue; + + virtio_clks[i].clk_id = i; + virtio_clks[i].vclk = vclk; + init.name = desc->clk_names[i]; + virtio_clks[i].hw.init = &init; + ret = devm_clk_hw_register(&vdev->dev, + &virtio_clks[i].hw); + if (ret) { + dev_err(&vdev->dev, "fail to register clock\n"); + goto err_clk_register; + } + } + } else { + init.name = name; + + for (i = 0; i < config.num_clks; i++) { + virtio_clks[i].clk_id = i; + virtio_clks[i].vclk = vclk; + snprintf(name, sizeof(name), "virtio_%d_%d", + instance, i); + virtio_clks[i].hw.init = &init; + ret = devm_clk_hw_register(&vdev->dev, + &virtio_clks[i].hw); + if (ret) { + dev_err(&vdev->dev, "fail to register clock\n"); + goto err_clk_register; + } + } + } + + ret = of_clk_add_hw_provider(vdev->dev.parent->of_node, + of_clk_hw_virtio_get, vclk); + if (ret) { + dev_err(&vdev->dev, "failed to add clock provider\n"); + goto err_clk_register; + } + + if (vclk->num_resets > 0) { + vclk->rcdev.of_node = vdev->dev.parent->of_node; + vclk->rcdev.ops = &virtio_reset_ops; + vclk->rcdev.owner = vdev->dev.driver->owner; + vclk->rcdev.nr_resets = vclk->num_resets; + ret = devm_reset_controller_register(&vdev->dev, &vclk->rcdev); + if (ret) + goto err_rst_register; + } + + instance++; + + dev_info(&vdev->dev, "Registered virtio clocks (%s)\n", config.name); + + return 0; + +err_rst_register: + of_clk_del_provider(vdev->dev.parent->of_node); +err_clk_register: +err_kcalloc: +err_find_desc: + vdev->config->del_vqs(vdev); + return ret; +} + +static const struct virtio_device_id id_table[] = { + { VIRTIO_ID_CLOCK, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static unsigned int features[] = { + VIRTIO_CLK_F_RESET, + VIRTIO_CLK_F_NAME, +}; + +static struct virtio_driver virtio_clk_driver = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_clk_probe, +}; + +static int __init virtio_clk_init(void) +{ + return register_virtio_driver(&virtio_clk_driver); +} + +static void __exit virtio_clk_fini(void) +{ + unregister_virtio_driver(&virtio_clk_driver); +} +subsys_initcall_sync(virtio_clk_init); +module_exit(virtio_clk_fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio clock driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/virtio_clk_common.h b/drivers/clk/qcom/virtio_clk_common.h new file mode 100644 index 000000000000..b8f7286de268 --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_common.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ + +#ifndef __VIRTIO_CLK_COMMON__ +#define __VIRTIO_CLK_COMMON__ + +#include + +/* + * struct clk_virtio_desc - virtio clock descriptor + * clk_names: the pointer of clock name pointer + * num_clks: number of clocks + * reset_names: the pointer of reset name pointer + * num_resets: number of resets + */ +struct clk_virtio_desc { + const char * const *clk_names; + size_t num_clks; + const char * const *reset_names; + size_t num_resets; +}; + +extern const struct clk_virtio_desc clk_virtio_sm8150_gcc; +extern const struct clk_virtio_desc clk_virtio_sm8150_scc; +extern const struct clk_virtio_desc clk_virtio_sm6150_gcc; +extern const struct clk_virtio_desc clk_virtio_sm6150_scc; +extern const struct clk_virtio_desc clk_virtio_sa8195p_gcc; + +#endif diff --git a/drivers/clk/qcom/virtio_clk_sa8195p.c b/drivers/clk/qcom/virtio_clk_sa8195p.c new file mode 100644 index 000000000000..08069594c424 --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_sa8195p.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "virtio_clk_common.h" + +static const char * const sa8195p_gcc_virtio_clocks[] = { + [GCC_QUPV3_WRAP0_S0_CLK] = "gcc_qupv3_wrap0_s0_clk", + [GCC_QUPV3_WRAP0_S1_CLK] = "gcc_qupv3_wrap0_s1_clk", + [GCC_QUPV3_WRAP0_S2_CLK] = "gcc_qupv3_wrap0_s2_clk", + [GCC_QUPV3_WRAP0_S3_CLK] = "gcc_qupv3_wrap0_s3_clk", + [GCC_QUPV3_WRAP0_S4_CLK] = "gcc_qupv3_wrap0_s4_clk", + [GCC_QUPV3_WRAP0_S5_CLK] = "gcc_qupv3_wrap0_s5_clk", + [GCC_QUPV3_WRAP0_S6_CLK] = "gcc_qupv3_wrap0_s6_clk", + [GCC_QUPV3_WRAP0_S7_CLK] = "gcc_qupv3_wrap0_s7_clk", + [GCC_QUPV3_WRAP1_S0_CLK] = "gcc_qupv3_wrap1_s0_clk", + [GCC_QUPV3_WRAP1_S1_CLK] = "gcc_qupv3_wrap1_s1_clk", + [GCC_QUPV3_WRAP1_S2_CLK] = "gcc_qupv3_wrap1_s2_clk", + [GCC_QUPV3_WRAP1_S3_CLK] = "gcc_qupv3_wrap1_s3_clk", + [GCC_QUPV3_WRAP1_S4_CLK] = "gcc_qupv3_wrap1_s4_clk", + [GCC_QUPV3_WRAP1_S5_CLK] = "gcc_qupv3_wrap1_s5_clk", + [GCC_QUPV3_WRAP2_S0_CLK] = "gcc_qupv3_wrap2_s0_clk", + [GCC_QUPV3_WRAP2_S1_CLK] = "gcc_qupv3_wrap2_s1_clk", + [GCC_QUPV3_WRAP2_S2_CLK] = "gcc_qupv3_wrap2_s2_clk", + [GCC_QUPV3_WRAP2_S3_CLK] = "gcc_qupv3_wrap2_s3_clk", + [GCC_QUPV3_WRAP2_S4_CLK] = "gcc_qupv3_wrap2_s4_clk", + [GCC_QUPV3_WRAP2_S5_CLK] = "gcc_qupv3_wrap2_s5_clk", + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = "gcc_qupv3_wrap_0_m_ahb_clk", + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = "gcc_qupv3_wrap_0_s_ahb_clk", + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = "gcc_qupv3_wrap_1_m_ahb_clk", + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = "gcc_qupv3_wrap_1_s_ahb_clk", + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = "gcc_qupv3_wrap_2_m_ahb_clk", + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = "gcc_qupv3_wrap_2_s_ahb_clk", + [GCC_USB30_PRIM_MASTER_CLK] = "gcc_usb30_prim_master_clk", + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = "gcc_cfg_noc_usb3_prim_axi_clk", + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = "gcc_aggre_usb3_prim_axi_clk", + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = "gcc_usb30_prim_mock_utmi_clk", + [GCC_USB30_PRIM_SLEEP_CLK] = "gcc_usb30_prim_sleep_clk", + [GCC_USB3_PRIM_PHY_AUX_CLK] = "gcc_usb3_prim_phy_aux_clk", + [GCC_USB3_PRIM_PHY_PIPE_CLK] = "gcc_usb3_prim_phy_pipe_clk", + [GCC_USB3_PRIM_CLKREF_CLK] = "gcc_usb3_prim_clkref_en", + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = "gcc_usb3_prim_phy_com_aux_clk", + [GCC_USB30_SEC_MASTER_CLK] = "gcc_usb30_sec_master_clk", + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = "gcc_cfg_noc_usb3_sec_axi_clk", + [GCC_AGGRE_USB3_SEC_AXI_CLK] = "gcc_aggre_usb3_sec_axi_clk", + [GCC_USB30_SEC_MOCK_UTMI_CLK] = "gcc_usb30_sec_mock_utmi_clk", + [GCC_USB30_SEC_SLEEP_CLK] = "gcc_usb30_sec_sleep_clk", + [GCC_USB3_SEC_PHY_AUX_CLK] = "gcc_usb3_sec_phy_aux_clk", + [GCC_USB3_SEC_PHY_PIPE_CLK] = "gcc_usb3_sec_phy_pipe_clk", + [GCC_USB3_SEC_CLKREF_CLK] = "gcc_usb3_sec_clkref_en", + [GCC_USB3_SEC_PHY_COM_AUX_CLK] = "gcc_usb3_sec_phy_com_aux_clk", + [GCC_PCIE_0_PIPE_CLK] = "gcc_pcie_0_pipe_clk", + [GCC_PCIE_0_AUX_CLK] = "gcc_pcie_0_aux_clk", + [GCC_PCIE_0_CFG_AHB_CLK] = "gcc_pcie_0_cfg_ahb_clk", + [GCC_PCIE_0_MSTR_AXI_CLK] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", + [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_PCIE_1_PIPE_CLK] = "gcc_pcie_1_pipe_clk", + [GCC_PCIE_1_AUX_CLK] = "gcc_pcie_1_aux_clk", + [GCC_PCIE_1_CFG_AHB_CLK] = "gcc_pcie_1_cfg_ahb_clk", + [GCC_PCIE_1_MSTR_AXI_CLK] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_SLV_AXI_CLK] = "gcc_pcie_1_slv_axi_clk", + [GCC_PCIE_1_CLKREF_CLK] = "gcc_pcie_1_clkref_en", + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = "gcc_pcie_1_slv_q2a_axi_clk", + [GCC_PCIE_2_PIPE_CLK] = "gcc_pcie_2_pipe_clk", + [GCC_PCIE_2_AUX_CLK] = "gcc_pcie_2_aux_clk", + [GCC_PCIE_2_CFG_AHB_CLK] = "gcc_pcie_2_cfg_ahb_clk", + [GCC_PCIE_2_MSTR_AXI_CLK] = "gcc_pcie_2_mstr_axi_clk", + [GCC_PCIE_2_SLV_AXI_CLK] = "gcc_pcie_2_slv_axi_clk", + [GCC_PCIE_2_CLKREF_CLK] = "gcc_pcie_2_clkref_en", + [GCC_PCIE_2_SLV_Q2A_AXI_CLK] = "gcc_pcie_2_slv_q2a_axi_clk", + [GCC_PCIE_3_PIPE_CLK] = "gcc_pcie_3_pipe_clk", + [GCC_PCIE_3_AUX_CLK] = "gcc_pcie_3_aux_clk", + [GCC_PCIE_3_CFG_AHB_CLK] = "gcc_pcie_3_cfg_ahb_clk", + [GCC_PCIE_3_MSTR_AXI_CLK] = "gcc_pcie_3_mstr_axi_clk", + [GCC_PCIE_3_SLV_AXI_CLK] = "gcc_pcie_3_slv_axi_clk", + [GCC_PCIE_3_CLKREF_CLK] = "gcc_pcie_3_clkref_en", + [GCC_PCIE_3_SLV_Q2A_AXI_CLK] = "gcc_pcie_3_slv_q2a_axi_clk", + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = "gcc_aggre_noc_pcie_tbu_clk", + [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE1_PHY_REFGEN_CLK] = "gcc_pcie1_phy_refgen_clk", + [GCC_PCIE2_PHY_REFGEN_CLK] = "gcc_pcie2_phy_refgen_clk", + [GCC_PCIE3_PHY_REFGEN_CLK] = "gcc_pcie3_phy_refgen_clk", + [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", + [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", + [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", + [GCC_PRNG_AHB_CLK] = "gcc_prng_ahb_clk", +}; + +static const char * const sa8195p_gcc_virtio_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = "gcc_qusb2phy_prim_bcr", + [GCC_QUSB2PHY_SEC_BCR] = "gcc_qusb2phy_sec_bcr", + [GCC_USB30_PRIM_BCR] = "gcc_usb30_prim_master_clk", + [GCC_USB30_SEC_BCR] = "gcc_usb30_sec_master_clk", + [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", + [GCC_PCIE_1_BCR] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_PHY_BCR] = "gcc_pcie_1_phy_bcr", + [GCC_PCIE_2_BCR] = "gcc_pcie_2_mstr_axi_clk", + [GCC_PCIE_2_PHY_BCR] = "gcc_pcie_2_phy_bcr", + [GCC_PCIE_3_BCR] = "gcc_pcie_3_mstr_axi_clk", + [GCC_PCIE_3_PHY_BCR] = "gcc_pcie_3_phy_bcr", +}; + +const struct clk_virtio_desc clk_virtio_sa8195p_gcc = { + .clk_names = sa8195p_gcc_virtio_clocks, + .num_clks = ARRAY_SIZE(sa8195p_gcc_virtio_clocks), + .reset_names = sa8195p_gcc_virtio_resets, + .num_resets = ARRAY_SIZE(sa8195p_gcc_virtio_resets), +}; +EXPORT_SYMBOL(clk_virtio_sa8195p_gcc); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/virtio_clk_sm6150.c b/drivers/clk/qcom/virtio_clk_sm6150.c new file mode 100644 index 000000000000..552d78c8f5f4 --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_sm6150.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "virtio_clk_common.h" + +static const char * const sm6150_gcc_virtio_clocks[] = { + [GCC_QUPV3_WRAP0_S0_CLK] = "gcc_qupv3_wrap0_s0_clk", + [GCC_QUPV3_WRAP0_S1_CLK] = "gcc_qupv3_wrap0_s1_clk", + [GCC_QUPV3_WRAP0_S2_CLK] = "gcc_qupv3_wrap0_s2_clk", + [GCC_QUPV3_WRAP0_S3_CLK] = "gcc_qupv3_wrap0_s3_clk", + [GCC_QUPV3_WRAP0_S4_CLK] = "gcc_qupv3_wrap0_s4_clk", + [GCC_QUPV3_WRAP0_S5_CLK] = "gcc_qupv3_wrap0_s5_clk", + [GCC_QUPV3_WRAP1_S0_CLK] = "gcc_qupv3_wrap1_s0_clk", + [GCC_QUPV3_WRAP1_S1_CLK] = "gcc_qupv3_wrap1_s1_clk", + [GCC_QUPV3_WRAP1_S2_CLK] = "gcc_qupv3_wrap1_s2_clk", + [GCC_QUPV3_WRAP1_S3_CLK] = "gcc_qupv3_wrap1_s3_clk", + [GCC_QUPV3_WRAP1_S4_CLK] = "gcc_qupv3_wrap1_s4_clk", + [GCC_QUPV3_WRAP1_S5_CLK] = "gcc_qupv3_wrap1_s5_clk", + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = "gcc_qupv3_wrap_0_m_ahb_clk", + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = "gcc_qupv3_wrap_0_s_ahb_clk", + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = "gcc_qupv3_wrap_1_m_ahb_clk", + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = "gcc_qupv3_wrap_1_s_ahb_clk", + [GCC_USB30_PRIM_MASTER_CLK] = "gcc_usb30_prim_master_clk", + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = "gcc_cfg_noc_usb3_prim_axi_clk", + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = "gcc_aggre_usb3_prim_axi_clk", + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = "gcc_usb30_prim_mock_utmi_clk", + [GCC_USB30_PRIM_SLEEP_CLK] = "gcc_usb30_prim_sleep_clk", + [GCC_USB3_SEC_CLKREF_CLK] = "gcc_usb3_sec_clkref_en", + [GCC_USB3_PRIM_PHY_AUX_CLK] = "gcc_usb3_prim_phy_aux_clk", + [GCC_USB3_PRIM_PHY_PIPE_CLK] = "gcc_usb3_prim_phy_pipe_clk", + [GCC_USB3_PRIM_CLKREF_CLK] = "gcc_usb3_prim_clkref_en", + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = "gcc_usb3_prim_phy_com_aux_clk", + [GCC_AHB2PHY_WEST_CLK] = "gcc_ahb2phy_west_clk", + [GCC_PCIE_0_PIPE_CLK] = "gcc_pcie_0_pipe_clk", + [GCC_PCIE_0_AUX_CLK] = "gcc_pcie_0_aux_clk", + [GCC_PCIE_0_CFG_AHB_CLK] = "gcc_pcie_0_cfg_ahb_clk", + [GCC_PCIE_0_MSTR_AXI_CLK] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", + [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", + [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", + [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", + [GCC_PRNG_AHB_CLK] = "gcc_prng_ahb_clk", + [GCC_SDR_CORE_CLK] = "gcc_sdr_core_clk", + [GCC_SDR_WR0_MEM_CLK] = "gcc_sdr_wr0_mem_clk", + [GCC_SDR_WR1_MEM_CLK] = "gcc_sdr_wr1_mem_clk", + [GCC_SDR_WR2_MEM_CLK] = "gcc_sdr_wr2_mem_clk", + [GCC_SDR_CSR_HCLK] = "gcc_sdr_csr_hclk", + [GCC_SDR_PRI_MI2S_CLK] = "gcc_sdr_pri_mi2s_clk", + [GCC_SDR_SEC_MI2S_CLK] = "gcc_sdr_sec_mi2s_clk", +}; + +static const char * const sm6150_gcc_virtio_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = "gcc_qusb2phy_prim_bcr", + [GCC_QUSB2PHY_SEC_BCR] = "gcc_qusb2phy_sec_bcr", + [GCC_USB30_PRIM_BCR] = "gcc_usb30_prim_master_clk", + [GCC_USB2_PHY_SEC_BCR] = "gcc_usb2_phy_sec_bcr", + [GCC_USB3_DP_PHY_SEC_BCR] = "gcc_usb3_dp_phy_sec_bcr", + [GCC_USB3PHY_PHY_SEC_BCR] = "gcc_usb3phy_phy_sec_bcr", + [GCC_USB20_SEC_BCR] = "gcc_usb20_sec_master_clk", + [GCC_USB3_PHY_PRIM_SP0_BCR] = "gcc_usb3_phy_prim_sp0_bcr", + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = "gcc_usb3phy_phy_prim_sp0_bcr", + [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", +}; + +const struct clk_virtio_desc clk_virtio_sm6150_gcc = { + .clk_names = sm6150_gcc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm6150_gcc_virtio_clocks), + .reset_names = sm6150_gcc_virtio_resets, + .num_resets = ARRAY_SIZE(sm6150_gcc_virtio_resets), +}; +EXPORT_SYMBOL(clk_virtio_sm6150_gcc); + +static const char * const sm6150_scc_virtio_clocks[] = { + [SCC_QUPV3_SE0_CLK] = "scc_qupv3_se0_clk", + [SCC_QUPV3_SE1_CLK] = "scc_qupv3_se1_clk", + [SCC_QUPV3_SE2_CLK] = "scc_qupv3_se2_clk", + [SCC_QUPV3_SE3_CLK] = "scc_qupv3_se3_clk", + [SCC_QUPV3_M_HCLK_CLK] = "scc_qupv3_m_hclk_clk", + [SCC_QUPV3_S_HCLK_CLK] = "scc_qupv3_s_hclk_clk", +}; + +const struct clk_virtio_desc clk_virtio_sm6150_scc = { + .clk_names = sm6150_scc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm6150_scc_virtio_clocks), +}; +EXPORT_SYMBOL(clk_virtio_sm6150_scc); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/virtio_clk_sm8150.c b/drivers/clk/qcom/virtio_clk_sm8150.c new file mode 100644 index 000000000000..e492dc333837 --- /dev/null +++ b/drivers/clk/qcom/virtio_clk_sm8150.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "virtio_clk_common.h" + +static const char * const sm8150_gcc_virtio_clocks[] = { + [GCC_QUPV3_WRAP0_S0_CLK] = "gcc_qupv3_wrap0_s0_clk", + [GCC_QUPV3_WRAP0_S1_CLK] = "gcc_qupv3_wrap0_s1_clk", + [GCC_QUPV3_WRAP0_S2_CLK] = "gcc_qupv3_wrap0_s2_clk", + [GCC_QUPV3_WRAP0_S3_CLK] = "gcc_qupv3_wrap0_s3_clk", + [GCC_QUPV3_WRAP0_S4_CLK] = "gcc_qupv3_wrap0_s4_clk", + [GCC_QUPV3_WRAP0_S5_CLK] = "gcc_qupv3_wrap0_s5_clk", + [GCC_QUPV3_WRAP0_S6_CLK] = "gcc_qupv3_wrap0_s6_clk", + [GCC_QUPV3_WRAP0_S7_CLK] = "gcc_qupv3_wrap0_s7_clk", + [GCC_QUPV3_WRAP1_S0_CLK] = "gcc_qupv3_wrap1_s0_clk", + [GCC_QUPV3_WRAP1_S1_CLK] = "gcc_qupv3_wrap1_s1_clk", + [GCC_QUPV3_WRAP1_S2_CLK] = "gcc_qupv3_wrap1_s2_clk", + [GCC_QUPV3_WRAP1_S3_CLK] = "gcc_qupv3_wrap1_s3_clk", + [GCC_QUPV3_WRAP1_S4_CLK] = "gcc_qupv3_wrap1_s4_clk", + [GCC_QUPV3_WRAP1_S5_CLK] = "gcc_qupv3_wrap1_s5_clk", + [GCC_QUPV3_WRAP2_S0_CLK] = "gcc_qupv3_wrap2_s0_clk", + [GCC_QUPV3_WRAP2_S1_CLK] = "gcc_qupv3_wrap2_s1_clk", + [GCC_QUPV3_WRAP2_S2_CLK] = "gcc_qupv3_wrap2_s2_clk", + [GCC_QUPV3_WRAP2_S3_CLK] = "gcc_qupv3_wrap2_s3_clk", + [GCC_QUPV3_WRAP2_S4_CLK] = "gcc_qupv3_wrap2_s4_clk", + [GCC_QUPV3_WRAP2_S5_CLK] = "gcc_qupv3_wrap2_s5_clk", + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = "gcc_qupv3_wrap_0_m_ahb_clk", + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = "gcc_qupv3_wrap_0_s_ahb_clk", + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = "gcc_qupv3_wrap_1_m_ahb_clk", + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = "gcc_qupv3_wrap_1_s_ahb_clk", + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = "gcc_qupv3_wrap_2_m_ahb_clk", + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = "gcc_qupv3_wrap_2_s_ahb_clk", + [GCC_USB30_PRIM_MASTER_CLK] = "gcc_usb30_prim_master_clk", + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = "gcc_cfg_noc_usb3_prim_axi_clk", + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = "gcc_aggre_usb3_prim_axi_clk", + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = "gcc_usb30_prim_mock_utmi_clk", + [GCC_USB30_PRIM_SLEEP_CLK] = "gcc_usb30_prim_sleep_clk", + [GCC_USB3_SEC_CLKREF_CLK] = "gcc_usb3_sec_clkref_en", + [GCC_USB3_PRIM_PHY_AUX_CLK] = "gcc_usb3_prim_phy_aux_clk", + [GCC_USB3_PRIM_PHY_PIPE_CLK] = "gcc_usb3_prim_phy_pipe_clk", + [GCC_USB3_PRIM_CLKREF_CLK] = "gcc_usb3_prim_clkref_en", + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = "gcc_usb3_prim_phy_com_aux_clk", + [GCC_USB30_SEC_MASTER_CLK] = "gcc_usb30_sec_master_clk", + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = "gcc_cfg_noc_usb3_sec_axi_clk", + [GCC_AGGRE_USB3_SEC_AXI_CLK] = "gcc_aggre_usb3_sec_axi_clk", + [GCC_USB30_SEC_MOCK_UTMI_CLK] = "gcc_usb30_sec_mock_utmi_clk", + [GCC_USB30_SEC_SLEEP_CLK] = "gcc_usb30_sec_sleep_clk", + [GCC_USB3_SEC_PHY_AUX_CLK] = "gcc_usb3_sec_phy_aux_clk", + [GCC_USB3_SEC_PHY_PIPE_CLK] = "gcc_usb3_sec_phy_pipe_clk", + [GCC_USB3_SEC_PHY_COM_AUX_CLK] = "gcc_usb3_sec_phy_com_aux_clk", + [GCC_PCIE_0_PIPE_CLK] = "gcc_pcie_0_pipe_clk", + [GCC_PCIE_0_AUX_CLK] = "gcc_pcie_0_aux_clk", + [GCC_PCIE_0_CFG_AHB_CLK] = "gcc_pcie_0_cfg_ahb_clk", + [GCC_PCIE_0_MSTR_AXI_CLK] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", + [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_PCIE_1_PIPE_CLK] = "gcc_pcie_1_pipe_clk", + [GCC_PCIE_1_AUX_CLK] = "gcc_pcie_1_aux_clk", + [GCC_PCIE_1_CFG_AHB_CLK] = "gcc_pcie_1_cfg_ahb_clk", + [GCC_PCIE_1_MSTR_AXI_CLK] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_SLV_AXI_CLK] = "gcc_pcie_1_slv_axi_clk", + [GCC_PCIE_1_CLKREF_CLK] = "gcc_pcie_1_clkref_en", + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = "gcc_pcie_1_slv_q2a_axi_clk", + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = "gcc_aggre_noc_pcie_tbu_clk", + [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE1_PHY_REFGEN_CLK] = "gcc_pcie1_phy_refgen_clk", + [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", + [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", + [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", + [GCC_PRNG_AHB_CLK] = "gcc_prng_ahb_clk", +}; + +static const char * const sm8150_gcc_virtio_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = "gcc_qusb2phy_prim_bcr", + [GCC_QUSB2PHY_SEC_BCR] = "gcc_qusb2phy_sec_bcr", + [GCC_USB3_PHY_PRIM_BCR] = "gcc_usb3_phy_prim_bcr", + [GCC_USB3_DP_PHY_PRIM_BCR] = "gcc_usb3_dp_phy_prim_bcr", + [GCC_USB3_PHY_SEC_BCR] = "gcc_usb3_phy_sec_bcr", + [GCC_USB3PHY_PHY_SEC_BCR] = "gcc_usb3phy_phy_sec_bcr", + [GCC_USB30_PRIM_BCR] = "gcc_usb30_prim_master_clk", + [GCC_USB30_SEC_BCR] = "gcc_usb30_sec_master_clk", + [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", + [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", + [GCC_PCIE_1_BCR] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_PHY_BCR] = "gcc_pcie_1_phy_bcr", +}; + +const struct clk_virtio_desc clk_virtio_sm8150_gcc = { + .clk_names = sm8150_gcc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm8150_gcc_virtio_clocks), + .reset_names = sm8150_gcc_virtio_resets, + .num_resets = ARRAY_SIZE(sm8150_gcc_virtio_resets), +}; +EXPORT_SYMBOL(clk_virtio_sm8150_gcc); + +static const char * const sm8150_scc_virtio_clocks[] = { + [SCC_QUPV3_SE0_CLK] = "scc_qupv3_se0_clk", + [SCC_QUPV3_SE1_CLK] = "scc_qupv3_se1_clk", + [SCC_QUPV3_SE2_CLK] = "scc_qupv3_se2_clk", + [SCC_QUPV3_SE3_CLK] = "scc_qupv3_se3_clk", + [SCC_QUPV3_M_HCLK_CLK] = "scc_qupv3_m_hclk_clk", + [SCC_QUPV3_S_HCLK_CLK] = "scc_qupv3_s_hclk_clk", +}; + +const struct clk_virtio_desc clk_virtio_sm8150_scc = { + .clk_names = sm8150_scc_virtio_clocks, + .num_clks = ARRAY_SIZE(sm8150_scc_virtio_clocks), +}; +EXPORT_SYMBOL(clk_virtio_sm8150_scc); + +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/virtio_clk.h b/include/linux/virtio_clk.h new file mode 100644 index 000000000000..0e60017860c3 --- /dev/null +++ b/include/linux/virtio_clk.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ + +#ifndef _LINUX_VIRTIO_CLK_H +#define _LINUX_VIRTIO_CLK_H + +#include +#include +#include +#include + +/* Virtio ID of clock */ +#define VIRTIO_ID_CLOCK 30 /* virtio clock */ + +/* Feature bits */ +#define VIRTIO_CLK_F_RESET 1 /* Support reset */ +#define VIRTIO_CLK_F_NAME 2 /* Support clock name */ + +/* Configuration layout */ +struct virtio_clk_config { + __u32 num_clks; + __u32 num_resets; + __u8 name[20]; +} __packed; + +/* Request/response message format */ +struct virtio_clk_msg { + u8 name[40]; + __virtio32 id; + __virtio32 type; + __virtio32 result; + __virtio32 data[4]; +}; + +/* Request type */ +#define VIRTIO_CLK_T_ENABLE 0 +#define VIRTIO_CLK_T_DISABLE 1 +#define VIRTIO_CLK_T_SET_RATE 2 +#define VIRTIO_CLK_T_GET_RATE 3 +#define VIRTIO_CLK_T_ROUND_RATE 4 +#define VIRTIO_CLK_T_RESET 5 +#define VIRTIO_CLK_T_SET_FLAGS 6 + +#endif /* _LINUX_VIRTIO_CLK_H */