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 <mm/core_memprot.h> 10 #include <types_ext.h> 11 12 #include "at91_clk.h" 13 14 #define MASTER_PRES_MASK 0x7 15 #define MASTER_PRES_MAX MASTER_PRES_MASK 16 #define MASTER_DIV_SHIFT 8 17 #define MASTER_DIV_MASK 0x7 18 19 struct clk_master { 20 vaddr_t base; 21 const struct clk_master_layout *layout; 22 const struct clk_master_charac *charac; 23 uint32_t *mux_table; 24 uint32_t mckr; 25 int chg_pid; 26 uint8_t div; 27 }; 28 29 static bool clk_master_ready(struct clk_master *master) 30 { 31 uint32_t status = io_read32(master->base + AT91_PMC_SR); 32 33 return status & AT91_PMC_MCKRDY; 34 } 35 36 static TEE_Result clk_master_enable(struct clk *clk) 37 { 38 struct clk_master *master = clk->priv; 39 40 while (!clk_master_ready(master)) 41 ; 42 43 return TEE_SUCCESS; 44 } 45 46 static unsigned long clk_master_div_get_rate(struct clk *clk, 47 unsigned long parent_rate) 48 { 49 uint8_t div = 1; 50 uint32_t mckr = 0; 51 unsigned long rate = parent_rate; 52 struct clk_master *master = clk->priv; 53 const struct clk_master_layout *layout = master->layout; 54 const struct clk_master_charac *charac = master->charac; 55 56 mckr = io_read32(master->base + master->layout->offset); 57 58 mckr &= layout->mask; 59 60 div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; 61 62 rate /= charac->divisors[div]; 63 64 if (rate < charac->output.min) 65 IMSG("master clk div is underclocked"); 66 else if (rate > charac->output.max) 67 IMSG("master clk div is overclocked"); 68 69 return rate; 70 } 71 72 static const struct clk_ops master_div_ops = { 73 .enable = clk_master_enable, 74 .get_rate = clk_master_div_get_rate, 75 }; 76 77 static unsigned long clk_master_pres_get_rate(struct clk *clk, 78 unsigned long parent_rate) 79 { 80 struct clk_master *master = clk->priv; 81 const struct clk_master_charac *charac = master->charac; 82 uint32_t val = 0; 83 unsigned int pres = 0; 84 85 val = io_read32(master->base + master->layout->offset); 86 87 pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK; 88 if (pres != 3 || !charac->have_div3_pres) 89 pres = BIT(pres); 90 91 return UDIV_ROUND_NEAREST(parent_rate, pres); 92 } 93 94 static size_t clk_master_pres_get_parent(struct clk *clk) 95 { 96 struct clk_master *master = clk->priv; 97 uint32_t mckr = 0; 98 99 mckr = io_read32(master->base + master->layout->offset); 100 101 return mckr & AT91_PMC_CSS; 102 } 103 104 static const struct clk_ops master_pres_ops = { 105 .enable = clk_master_enable, 106 .get_rate = clk_master_pres_get_rate, 107 .get_parent = clk_master_pres_get_parent, 108 }; 109 110 static struct clk * 111 at91_clk_register_master_internal(struct pmc_data *pmc, 112 const char *name, int num_parents, 113 struct clk **parents, 114 const struct clk_master_layout *layout, 115 const struct clk_master_charac *charac, 116 const struct clk_ops *ops, int chg_pid) 117 { 118 struct clk_master *master = NULL; 119 struct clk *clk = NULL; 120 121 if (!name || !num_parents || !parents) 122 return NULL; 123 124 clk = clk_alloc(name, ops, parents, num_parents); 125 if (!clk) 126 return NULL; 127 128 master = calloc(1, sizeof(*master)); 129 if (!master) { 130 clk_free(clk); 131 return NULL; 132 } 133 134 master->layout = layout; 135 master->charac = charac; 136 master->base = pmc->base; 137 master->chg_pid = chg_pid; 138 139 clk->priv = master; 140 clk->flags = CLK_SET_RATE_GATE; 141 142 if (clk_register(clk)) { 143 clk_free(clk); 144 free(master); 145 return NULL; 146 } 147 148 return clk; 149 } 150 151 struct clk * 152 at91_clk_register_master_pres(struct pmc_data *pmc, 153 const char *name, int num_parents, 154 struct clk **parents, 155 const struct clk_master_layout *layout, 156 const struct clk_master_charac *charac, 157 int chg_pid) 158 { 159 return at91_clk_register_master_internal(pmc, name, num_parents, 160 parents, layout, 161 charac, 162 &master_pres_ops, chg_pid); 163 } 164 165 struct clk * 166 at91_clk_register_master_div(struct pmc_data *pmc, 167 const char *name, struct clk *parent, 168 const struct clk_master_layout *layout, 169 const struct clk_master_charac *charac) 170 { 171 return at91_clk_register_master_internal(pmc, name, 1, 172 &parent, layout, 173 charac, 174 &master_div_ops, -1); 175 } 176 177 const struct clk_master_layout at91sam9x5_master_layout = { 178 .mask = 0x373, 179 .pres_shift = 4, 180 .offset = AT91_PMC_MCKR, 181 }; 182