1 // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2 /*
3  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4  *  Copyright (C) 2021 Microchip
5  */
6 
7 #include <io.h>
8 #include <kernel/delay.h>
9 #include <kernel/panic.h>
10 #include <mm/core_memprot.h>
11 #include <types_ext.h>
12 
13 #include "at91_clk.h"
14 
15 #define SYSTEM_MAX_ID		31
16 
17 #define SYSTEM_MAX_NAME_SZ	32
18 
19 struct clk_system {
20 	vaddr_t base;
21 	uint8_t id;
22 };
23 
is_pck(int id)24 static bool is_pck(int id)
25 {
26 	return (id >= 8) && (id <= 15);
27 }
28 
clk_system_ready(vaddr_t base,int id)29 static bool clk_system_ready(vaddr_t base, int id)
30 {
31 	uint32_t status = io_read32(base + AT91_PMC_SR);
32 
33 	return status & BIT(id);
34 }
35 
clk_system_enable(struct clk * clk)36 static TEE_Result clk_system_enable(struct clk *clk)
37 {
38 	struct clk_system *sys = clk->priv;
39 
40 	io_write32(sys->base + AT91_PMC_SCER, 1 << sys->id);
41 
42 	if (!is_pck(sys->id))
43 		return TEE_SUCCESS;
44 
45 	while (!clk_system_ready(sys->base, sys->id))
46 		;
47 
48 	return TEE_SUCCESS;
49 }
50 
clk_system_disable(struct clk * clk)51 static void clk_system_disable(struct clk *clk)
52 {
53 	struct clk_system *sys = clk->priv;
54 
55 	io_write32(sys->base + AT91_PMC_SCDR, 1 << sys->id);
56 }
57 
58 static const struct clk_ops system_ops = {
59 	.enable = clk_system_enable,
60 	.disable = clk_system_disable,
61 };
62 
63 struct clk *
at91_clk_register_system(struct pmc_data * pmc,const char * name,struct clk * parent,uint8_t id)64 at91_clk_register_system(struct pmc_data *pmc, const char *name,
65 			 struct clk *parent, uint8_t id)
66 {
67 	struct clk_system *sys = NULL;
68 	struct clk *clk = NULL;
69 
70 	if (!parent || id > SYSTEM_MAX_ID)
71 		return NULL;
72 
73 	clk = clk_alloc(name, &system_ops, &parent, 1);
74 	if (!clk)
75 		return NULL;
76 
77 	sys = calloc(1, sizeof(*sys));
78 	if (!sys) {
79 		clk_free(clk);
80 		return NULL;
81 	}
82 
83 	sys->id = id;
84 	sys->base = pmc->base;
85 
86 	clk->priv = sys;
87 
88 	if (clk_register(clk)) {
89 		clk_free(clk);
90 		free(sys);
91 		return NULL;
92 	}
93 
94 	return clk;
95 }
96