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 SAM9X5_USB_DIV_SHIFT 8 16 #define SAM9X5_USB_DIV_COUNT BIT32(4) 17 #define SAM9X5_USB_MAX_DIV (SAM9X5_USB_DIV_COUNT - 1) 18 19 #define SAM9X5_USBS_MASK BIT(0) 20 21 struct at91sam9x5_clk_usb { 22 vaddr_t base; 23 uint32_t usbs_mask; 24 }; 25 26 static unsigned long at91sam9x5_clk_usb_get_rate(struct clk *clk, 27 unsigned long parent_rate) 28 { 29 struct at91sam9x5_clk_usb *usb = clk->priv; 30 uint8_t usbdiv = 1; 31 unsigned int usbr = io_read32(usb->base + AT91_PMC_USB); 32 33 usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; 34 35 return UDIV_ROUND_NEAREST(parent_rate, (usbdiv + 1)); 36 } 37 38 static TEE_Result at91sam9x5_clk_usb_set_parent(struct clk *clk, size_t index) 39 { 40 struct at91sam9x5_clk_usb *usb = clk->priv; 41 42 if (index >= clk_get_num_parents(clk)) 43 return TEE_ERROR_BAD_PARAMETERS; 44 45 io_clrsetbits32(usb->base + AT91_PMC_USB, usb->usbs_mask, index); 46 47 return TEE_SUCCESS; 48 } 49 50 static size_t at91sam9x5_clk_usb_get_parent(struct clk *clk) 51 { 52 struct at91sam9x5_clk_usb *usb = clk->priv; 53 unsigned int usbr = io_read32(usb->base + AT91_PMC_USB); 54 55 return usbr & usb->usbs_mask; 56 } 57 58 static TEE_Result at91sam9x5_clk_usb_set_rate(struct clk *clk, 59 unsigned long rate, 60 unsigned long parent_rate) 61 { 62 struct at91sam9x5_clk_usb *usb = clk->priv; 63 unsigned long div = 1; 64 65 if (!rate) 66 return TEE_ERROR_BAD_PARAMETERS; 67 68 div = UDIV_ROUND_NEAREST(parent_rate, rate); 69 if (div > SAM9X5_USB_MAX_DIV + 1 || !div) 70 return TEE_ERROR_BAD_PARAMETERS; 71 72 io_clrsetbits32(usb->base + AT91_PMC_USB, AT91_PMC_OHCIUSBDIV, 73 (div - 1) << SAM9X5_USB_DIV_SHIFT); 74 75 return TEE_SUCCESS; 76 } 77 78 static const struct clk_ops at91sam9x5_usb_ops = { 79 .get_rate = at91sam9x5_clk_usb_get_rate, 80 .get_parent = at91sam9x5_clk_usb_get_parent, 81 .set_parent = at91sam9x5_clk_usb_set_parent, 82 .set_rate = at91sam9x5_clk_usb_set_rate, 83 }; 84 85 static struct clk * 86 _at91sam9x5_clk_register_usb(struct pmc_data *pmc, const char *name, 87 struct clk **parents, uint8_t num_parents, 88 uint32_t usbs_mask) 89 { 90 struct at91sam9x5_clk_usb *usb = NULL; 91 struct clk *clk = NULL; 92 93 clk = clk_alloc(name, &at91sam9x5_usb_ops, parents, num_parents); 94 if (!clk) 95 return NULL; 96 97 usb = calloc(1, sizeof(*usb)); 98 if (!usb) 99 return NULL; 100 101 usb->base = pmc->base; 102 usb->usbs_mask = usbs_mask; 103 104 clk->priv = usb; 105 clk->flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; 106 107 if (clk_register(clk)) { 108 clk_free(clk); 109 free(usb); 110 return NULL; 111 } 112 113 return clk; 114 } 115 116 struct clk * 117 at91sam9x5_clk_register_usb(struct pmc_data *pmc, const char *name, 118 struct clk **parents, uint8_t num_parents) 119 { 120 return _at91sam9x5_clk_register_usb(pmc, name, parents, 121 num_parents, SAM9X5_USBS_MASK); 122 } 123