1 // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause 2 /* 3 * Copyright (C) 2015 - 2021 Atmel Corporation, 4 * Nicolas Ferre <nicolas.ferre@atmel.com> 5 * 6 * Based on clk-programmable & clk-peripheral drivers by Boris BREZILLON. 7 */ 8 9 #include <io.h> 10 #include <kernel/delay.h> 11 #include <kernel/panic.h> 12 #include <mm/core_memprot.h> 13 #include <string.h> 14 #include <types_ext.h> 15 16 #include "at91_clk.h" 17 18 #define GENERATED_MAX_DIV 255 19 20 struct clk_generated { 21 vaddr_t base; 22 struct clk_range range; 23 uint32_t *mux_table; 24 uint32_t id; 25 uint32_t gckdiv; 26 const struct clk_pcr_layout *layout; 27 uint8_t parent_id; 28 int chg_pid; 29 }; 30 31 static TEE_Result clk_generated_enable(struct clk *clk) 32 { 33 struct clk_generated *gck = clk->priv; 34 35 io_write32(gck->base + gck->layout->offset, 36 (gck->id & gck->layout->pid_mask)); 37 io_clrsetbits32(gck->base + gck->layout->offset, 38 AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask | 39 gck->layout->cmd | AT91_PMC_PCR_GCKEN, 40 field_prep(gck->layout->gckcss_mask, gck->parent_id) | 41 gck->layout->cmd | 42 ((gck->gckdiv << AT91_PMC_PCR_GCKDIV_SHIFT) & 43 AT91_PMC_PCR_GCKDIV_MASK) | 44 AT91_PMC_PCR_GCKEN); 45 46 return TEE_SUCCESS; 47 } 48 49 static void clk_generated_disable(struct clk *clk) 50 { 51 struct clk_generated *gck = clk->priv; 52 53 io_write32(gck->base + gck->layout->offset, 54 gck->id & gck->layout->pid_mask); 55 io_clrsetbits32(gck->base + gck->layout->offset, AT91_PMC_PCR_GCKEN, 56 gck->layout->cmd); 57 } 58 59 static unsigned long 60 clk_generated_get_rate(struct clk *clk, unsigned long parent_rate) 61 { 62 struct clk_generated *gck = clk->priv; 63 64 return UDIV_ROUND_NEAREST(parent_rate, gck->gckdiv + 1); 65 } 66 67 /* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */ 68 static TEE_Result clk_generated_set_parent(struct clk *clk, size_t index) 69 { 70 struct clk_generated *gck = clk->priv; 71 72 if (index >= clk_get_num_parents(clk)) 73 return TEE_ERROR_BAD_PARAMETERS; 74 75 gck->parent_id = index; 76 77 return TEE_SUCCESS; 78 } 79 80 static size_t clk_generated_get_parent(struct clk *clk) 81 { 82 struct clk_generated *gck = clk->priv; 83 84 return gck->parent_id; 85 } 86 87 /* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */ 88 static TEE_Result clk_generated_set_rate(struct clk *clk, unsigned long rate, 89 unsigned long parent_rate) 90 { 91 struct clk_generated *gck = clk->priv; 92 uint32_t div = 1; 93 94 if (!rate) 95 return TEE_ERROR_BAD_PARAMETERS; 96 97 if (gck->range.max && rate > gck->range.max) 98 return TEE_ERROR_BAD_PARAMETERS; 99 100 div = UDIV_ROUND_NEAREST(parent_rate, rate); 101 if (div > GENERATED_MAX_DIV + 1 || !div) 102 return TEE_ERROR_GENERIC; 103 104 gck->gckdiv = div - 1; 105 return TEE_SUCCESS; 106 } 107 108 static const struct clk_ops generated_ops = { 109 .enable = clk_generated_enable, 110 .disable = clk_generated_disable, 111 .get_rate = clk_generated_get_rate, 112 .get_parent = clk_generated_get_parent, 113 .set_parent = clk_generated_set_parent, 114 .set_rate = clk_generated_set_rate, 115 }; 116 117 /** 118 * clk_generated_startup - Initialize a given clock to its default parent and 119 * divisor parameter. 120 * 121 * @gck: Generated clock to set the startup parameters for. 122 * 123 * Take parameters from the hardware and update local clock configuration 124 * accordingly. 125 */ 126 static void clk_generated_startup(struct clk_generated *gck) 127 { 128 uint32_t tmp = 0; 129 130 io_write32(gck->base + gck->layout->offset, 131 (gck->id & gck->layout->pid_mask)); 132 tmp = io_read32(gck->base + gck->layout->offset); 133 134 gck->parent_id = field_get(gck->layout->gckcss_mask, tmp); 135 gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK) >> 136 AT91_PMC_PCR_GCKDIV_SHIFT; 137 } 138 139 struct clk * 140 at91_clk_register_generated(struct pmc_data *pmc, 141 const struct clk_pcr_layout *layout, 142 const char *name, struct clk **parents, 143 uint8_t num_parents, uint8_t id, 144 const struct clk_range *range, 145 int chg_pid) 146 { 147 struct clk_generated *gck = NULL; 148 struct clk *clk = NULL; 149 150 clk = clk_alloc(name, &generated_ops, parents, num_parents); 151 if (!clk) 152 return NULL; 153 154 gck = calloc(1, sizeof(*gck)); 155 if (!gck) { 156 clk_free(clk); 157 return NULL; 158 } 159 160 clk->flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; 161 162 gck->id = id; 163 gck->base = pmc->base; 164 memcpy(&gck->range, range, sizeof(gck->range)); 165 gck->chg_pid = chg_pid; 166 gck->layout = layout; 167 168 clk->priv = gck; 169 170 clk_generated_startup(gck); 171 172 if (clk_register(clk)) { 173 clk_free(clk); 174 free(gck); 175 return NULL; 176 } 177 pmc_register_id(id); 178 179 return clk; 180 } 181