Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c5df454 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "clk: qcom: Add snapshot of virtio clock driver"

parents 542bc66c 162bc3cc
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -666,3 +666,12 @@ config SM_CAMCC_YUPIK
	  capturing pictures.

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.
+1 −0
Original line number Diff line number Diff line
@@ -97,3 +97,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
+621 −0
Original line number Diff line number Diff line
// 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 <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/virtio.h>
#include <linux/virtio_clk.h>
#include <linux/scatterlist.h>
#include <linux/clk-provider.h>
#include <linux/reset-controller.h>
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#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");
+29 −0
Original line number Diff line number Diff line
/* 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 <linux/types.h>

/*
 * 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
+118 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <dt-bindings/clock/qcom,gcc-scshrike.h>
#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");
Loading