diff options
Diffstat (limited to 'plat/imx/imx8mq/imx_rdc.c')
-rw-r--r-- | plat/imx/imx8mq/imx_rdc.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/plat/imx/imx8mq/imx_rdc.c b/plat/imx/imx8mq/imx_rdc.c new file mode 100644 index 00000000..3f1d259e --- /dev/null +++ b/plat/imx/imx8mq/imx_rdc.c @@ -0,0 +1,168 @@ +/* + * Copyright 2017 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <errno.h> +#include <stdlib.h> +#include <stdint.h> +#include <platform_def.h> +#include <utils_def.h> +#include <imx_rdc.h> +#include <mmio.h> + +/* + * Read RDC settings for one peripheral + * read the given domains field and lock bit + * for the given PDAP index [0..118] + */ +int imx_rdc_get_pdap(struct rdc_pdap_conf *p) +{ + struct imx_rdc_regs *imx_rdc = (struct imx_rdc_regs *)IMX_RDC_BASE; + uint32_t reg = 0; + + reg = mmio_read_32((uintptr_t)&imx_rdc->pdap[p->index]); + p->lock = (reg & RDC_PDAP_LCK_MASK) >> RDC_PDAP_LCK_SHIFT; + p->domains = reg & 0xFF; + + return 0; +} + +/* + * Write RDC settings for one peripheral + * Check before write if is already locked then skip + */ +int imx_rdc_set_pdap(struct rdc_pdap_conf *p) +{ + struct imx_rdc_regs *imx_rdc = (struct imx_rdc_regs *)IMX_RDC_BASE; + struct rdc_pdap_conf r; + uint32_t i, reg = 0; + uint8_t multi_domain = 0; + + /* Check if locked */ + r.index = p->index; + imx_rdc_get_pdap(&r); + if (r.lock) { + WARN("RDC_PDAPn %d is already locked \n", p->index); + return -ENOENT; + } + + /* Check if no domain assigned */ + if (p->domains == 0) + return -EINVAL; + reg |= p->domains; + + /* Check if SREQ is needed */ + for (i = 0; i < 7; i += 2) + multi_domain += ((p->domains >> i) & 0x3) ? 1 : 0; + if (multi_domain > 1) + reg |= RDC_PDAP_SREQ_MASK; + /* Setup Lock from input */ + reg |= p->lock << RDC_PDAP_LCK_SHIFT; + mmio_write_32((uintptr_t)&imx_rdc->pdap[p->index], reg); + + return 0; +} + +/* + * Setup RDC settings for multiple peripherals + */ +int imx_rdc_set_peripherals(struct rdc_pdap_conf *peripherals_list, + uint32_t count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = imx_rdc_set_pdap(&peripherals_list[i]); + if (ret) + return ret; + } + + return 0; +} + +/* + * Read RDC setting for one master + * For the given index in p.index it returns the lock bit + * and the domain field into p structure. + */ +int imx_rdc_get_mda(struct rdc_mda_conf *p) +{ + struct imx_rdc_regs *imx_rdc = (struct imx_rdc_regs *)IMX_RDC_BASE; + uint32_t reg = 0; + + reg = mmio_read_32((uintptr_t)&imx_rdc->mda[p->index]); + p->domain = reg & RDC_MDA_DID_MASK; + p->lock = (reg & RDC_MDA_LCK_MASK) >> RDC_MDA_LCK_SHIFT; + return 0; +} + +/* + * Write RDC setting for one master + */ +int imx_rdc_set_mda(struct rdc_mda_conf *p) +{ + struct imx_rdc_regs *imx_rdc = (struct imx_rdc_regs *)IMX_RDC_BASE; + struct rdc_mda_conf r; + uint32_t reg = 0; + int ret = 0; + + /* Check if it is locked */ + r.index = p->index; + imx_rdc_get_mda(&r); + if (!r.lock) { + reg = (p->domain & RDC_MDA_DID_MASK) + | ((p->lock << RDC_MDA_LCK_SHIFT) & RDC_MDA_LCK_MASK); + NOTICE("imx_rdc_setup_mda(): write addr=0x%p, reg=0x%x\n", + &imx_rdc->mda[p->index], reg); + mmio_write_32((uintptr_t)&imx_rdc->mda[p->index], reg); + } else { + WARN("RDC_MDAn %d is already locked \n", p->index); + ret = -ENOENT; + } + + return ret; +} + +/* + * Setup RDC settings for multiple masters + */ +int imx_rdc_set_masters(struct rdc_mda_conf *masters_list, uint32_t count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = imx_rdc_set_mda(&masters_list[i]); + if (ret) + break; + } + + return ret; +} + +/* Default peripherals settings as an example */ +static struct rdc_pdap_conf periph_config[] = { + {RDC_PDAP_GPIO1, 0x3, 0}, + {RDC_PDAP_GPIO2, 0x3, 0}, + {RDC_PDAP_GPIO3, 0x3, 0}, + {RDC_PDAP_GPIO4, 0x3, 0}, + {RDC_PDAP_GPIO5, 0x3, 0}, +}; + +/* Default masters settings as an example */ +static struct rdc_mda_conf masters_config[] = { + {RDC_MDA_A53, 0, 0}, + {RDC_MDA_CAAM, 0, 0}, +}; + +void imx_rdc_set_peripherals_default(void) +{ + imx_rdc_set_peripherals(periph_config, ARRAY_SIZE(periph_config)); +} + +void imx_rdc_set_masters_default(void) +{ + imx_rdc_set_masters(masters_config, ARRAY_SIZE(masters_config)); +} |