cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clk-sun4i-display.c (5986B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2015 Maxime Ripard
      4 *
      5 * Maxime Ripard <maxime.ripard@free-electrons.com>
      6 */
      7
      8#include <linux/clk-provider.h>
      9#include <linux/io.h>
     10#include <linux/kernel.h>
     11#include <linux/of_address.h>
     12#include <linux/reset-controller.h>
     13#include <linux/slab.h>
     14#include <linux/spinlock.h>
     15
     16struct sun4i_a10_display_clk_data {
     17	bool	has_div;
     18	u8	num_rst;
     19	u8	parents;
     20
     21	u8	offset_en;
     22	u8	offset_div;
     23	u8	offset_mux;
     24	u8	offset_rst;
     25
     26	u8	width_div;
     27	u8	width_mux;
     28
     29	u32	flags;
     30};
     31
     32struct reset_data {
     33	void __iomem			*reg;
     34	spinlock_t			*lock;
     35	struct reset_controller_dev	rcdev;
     36	u8				offset;
     37};
     38
     39static DEFINE_SPINLOCK(sun4i_a10_display_lock);
     40
     41static inline struct reset_data *rcdev_to_reset_data(struct reset_controller_dev *rcdev)
     42{
     43	return container_of(rcdev, struct reset_data, rcdev);
     44};
     45
     46static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev,
     47				    unsigned long id)
     48{
     49	struct reset_data *data = rcdev_to_reset_data(rcdev);
     50	unsigned long flags;
     51	u32 reg;
     52
     53	spin_lock_irqsave(data->lock, flags);
     54
     55	reg = readl(data->reg);
     56	writel(reg & ~BIT(data->offset + id), data->reg);
     57
     58	spin_unlock_irqrestore(data->lock, flags);
     59
     60	return 0;
     61}
     62
     63static int sun4i_a10_display_deassert(struct reset_controller_dev *rcdev,
     64				      unsigned long id)
     65{
     66	struct reset_data *data = rcdev_to_reset_data(rcdev);
     67	unsigned long flags;
     68	u32 reg;
     69
     70	spin_lock_irqsave(data->lock, flags);
     71
     72	reg = readl(data->reg);
     73	writel(reg | BIT(data->offset + id), data->reg);
     74
     75	spin_unlock_irqrestore(data->lock, flags);
     76
     77	return 0;
     78}
     79
     80static int sun4i_a10_display_status(struct reset_controller_dev *rcdev,
     81				    unsigned long id)
     82{
     83	struct reset_data *data = rcdev_to_reset_data(rcdev);
     84
     85	return !(readl(data->reg) & BIT(data->offset + id));
     86}
     87
     88static const struct reset_control_ops sun4i_a10_display_reset_ops = {
     89	.assert		= sun4i_a10_display_assert,
     90	.deassert	= sun4i_a10_display_deassert,
     91	.status		= sun4i_a10_display_status,
     92};
     93
     94static int sun4i_a10_display_reset_xlate(struct reset_controller_dev *rcdev,
     95					 const struct of_phandle_args *spec)
     96{
     97	/* We only have a single reset signal */
     98	return 0;
     99}
    100
    101static void __init sun4i_a10_display_init(struct device_node *node,
    102					  const struct sun4i_a10_display_clk_data *data)
    103{
    104	const char *parents[4];
    105	const char *clk_name = node->name;
    106	struct reset_data *reset_data;
    107	struct clk_divider *div = NULL;
    108	struct clk_gate *gate;
    109	struct resource res;
    110	struct clk_mux *mux;
    111	void __iomem *reg;
    112	struct clk *clk;
    113	int ret;
    114
    115	of_property_read_string(node, "clock-output-names", &clk_name);
    116
    117	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
    118	if (IS_ERR(reg)) {
    119		pr_err("%s: Could not map the clock registers\n", clk_name);
    120		return;
    121	}
    122
    123	ret = of_clk_parent_fill(node, parents, data->parents);
    124	if (ret != data->parents) {
    125		pr_err("%s: Could not retrieve the parents\n", clk_name);
    126		goto unmap;
    127	}
    128
    129	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
    130	if (!mux)
    131		goto unmap;
    132
    133	mux->reg = reg;
    134	mux->shift = data->offset_mux;
    135	mux->mask = (1 << data->width_mux) - 1;
    136	mux->lock = &sun4i_a10_display_lock;
    137
    138	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
    139	if (!gate)
    140		goto free_mux;
    141
    142	gate->reg = reg;
    143	gate->bit_idx = data->offset_en;
    144	gate->lock = &sun4i_a10_display_lock;
    145
    146	if (data->has_div) {
    147		div = kzalloc(sizeof(*div), GFP_KERNEL);
    148		if (!div)
    149			goto free_gate;
    150
    151		div->reg = reg;
    152		div->shift = data->offset_div;
    153		div->width = data->width_div;
    154		div->lock = &sun4i_a10_display_lock;
    155	}
    156
    157	clk = clk_register_composite(NULL, clk_name,
    158				     parents, data->parents,
    159				     &mux->hw, &clk_mux_ops,
    160				     data->has_div ? &div->hw : NULL,
    161				     data->has_div ? &clk_divider_ops : NULL,
    162				     &gate->hw, &clk_gate_ops,
    163				     data->flags);
    164	if (IS_ERR(clk)) {
    165		pr_err("%s: Couldn't register the clock\n", clk_name);
    166		goto free_div;
    167	}
    168
    169	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
    170	if (ret) {
    171		pr_err("%s: Couldn't register DT provider\n", clk_name);
    172		goto free_clk;
    173	}
    174
    175	if (!data->num_rst)
    176		return;
    177
    178	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
    179	if (!reset_data)
    180		goto free_of_clk;
    181
    182	reset_data->reg = reg;
    183	reset_data->offset = data->offset_rst;
    184	reset_data->lock = &sun4i_a10_display_lock;
    185	reset_data->rcdev.nr_resets = data->num_rst;
    186	reset_data->rcdev.ops = &sun4i_a10_display_reset_ops;
    187	reset_data->rcdev.of_node = node;
    188
    189	if (data->num_rst == 1) {
    190		reset_data->rcdev.of_reset_n_cells = 0;
    191		reset_data->rcdev.of_xlate = &sun4i_a10_display_reset_xlate;
    192	} else {
    193		reset_data->rcdev.of_reset_n_cells = 1;
    194	}
    195
    196	if (reset_controller_register(&reset_data->rcdev)) {
    197		pr_err("%s: Couldn't register the reset controller\n",
    198		       clk_name);
    199		goto free_reset;
    200	}
    201
    202	return;
    203
    204free_reset:
    205	kfree(reset_data);
    206free_of_clk:
    207	of_clk_del_provider(node);
    208free_clk:
    209	clk_unregister_composite(clk);
    210free_div:
    211	kfree(div);
    212free_gate:
    213	kfree(gate);
    214free_mux:
    215	kfree(mux);
    216unmap:
    217	iounmap(reg);
    218	of_address_to_resource(node, 0, &res);
    219	release_mem_region(res.start, resource_size(&res));
    220}
    221
    222static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initconst = {
    223	.num_rst	= 2,
    224	.parents	= 4,
    225	.offset_en	= 31,
    226	.offset_rst	= 29,
    227	.offset_mux	= 24,
    228	.width_mux	= 2,
    229	.flags		= CLK_SET_RATE_PARENT,
    230};
    231
    232static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node)
    233{
    234	sun4i_a10_display_init(node, &sun4i_a10_tcon_ch0_data);
    235}
    236CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk",
    237	       sun4i_a10_tcon_ch0_setup);
    238
    239static const struct sun4i_a10_display_clk_data sun4i_a10_display_data __initconst = {
    240	.has_div	= true,
    241	.num_rst	= 1,
    242	.parents	= 3,
    243	.offset_en	= 31,
    244	.offset_rst	= 30,
    245	.offset_mux	= 24,
    246	.offset_div	= 0,
    247	.width_mux	= 2,
    248	.width_div	= 4,
    249};
    250
    251static void __init sun4i_a10_display_setup(struct device_node *node)
    252{
    253	sun4i_a10_display_init(node, &sun4i_a10_display_data);
    254}
    255CLK_OF_DECLARE(sun4i_a10_display, "allwinner,sun4i-a10-display-clk",
    256	       sun4i_a10_display_setup);