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