Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:49

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2017 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #include <bsp.h>
0029 #include <bsp/bootcard.h>
0030 #include <bsp/fatal.h>
0031 #include <bsp/fdt.h>
0032 #include <bsp/irq-generic.h>
0033 #include <bsp/linker-symbols.h>
0034 #include <dev/clock/arm-generic-timer.h>
0035 #include <libcpu/arm-cp15.h>
0036 #include <arm/freescale/imx/imx6ul_ccmreg.h>
0037 
0038 #include <libfdt.h>
0039 
0040 #define MAGIC_IRQ_OFFSET 32
0041 
0042 void *imx_get_reg_of_node(const void *fdt, int node)
0043 {
0044   int len;
0045   const uint32_t *val;
0046 
0047   val = fdt_getprop(fdt, node, "reg", &len);
0048   if (val == NULL || len < 4) {
0049     return NULL;
0050   }
0051 
0052   return (void *) fdt32_to_cpu(val[0]);
0053 }
0054 
0055 rtems_vector_number imx_get_irq_of_node(
0056   const void *fdt,
0057   int node,
0058   size_t index
0059 )
0060 {
0061   int len;
0062   const uint32_t *val;
0063 
0064   val = fdt_getprop(fdt, node, "interrupts", &len);
0065   if (val == NULL || len < (int) ((index + 1) * 12)) {
0066     return BSP_INTERRUPT_VECTOR_INVALID;
0067   }
0068 
0069   return fdt32_to_cpu(val[index * 3 + 1]) + MAGIC_IRQ_OFFSET;
0070 }
0071 
0072 uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells)
0073 {
0074   return intr[1] + MAGIC_IRQ_OFFSET;
0075 }
0076 
0077 static bool imx_is_imx6(const void *fdt)
0078 {
0079   /*
0080    * At the moment: Check for some compatible strings that should be there
0081    * somewhere in every fdt.
0082    *
0083    * FIXME: It would be nice if some CPU-ID could be used instead. But I didn't
0084    * find one.
0085    */
0086   int node;
0087 
0088   node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ul");
0089   if (node >= 0) {
0090     return true;
0091   }
0092 
0093   node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ull");
0094   if (node >= 0) {
0095     return true;
0096   }
0097 
0098   return false;
0099 }
0100 
0101 #define SYSCNT_CNTCR          (0x0)
0102 #define SYSCNT_CNTCR_ENABLE   (1 << 0)
0103 #define SYSCNT_CNTCR_HDBG     (1 << 1)
0104 #define SYSCNT_CNTCR_FCREQ(n) (1 << (8 + (n)))
0105 #define SYSCNT_CNTFID(n)      (0x20 + 4 * (n))
0106 
0107 static uint32_t imx_syscnt_enable_and_return_frequency(const void *fdt)
0108 {
0109   uint32_t freq;
0110   volatile void *syscnt_base;
0111 
0112   /* That's not in the usual FDTs. Sorry for falling back to a magic value. */
0113   if (imx_is_imx6(fdt)) {
0114     syscnt_base = (void *)0x021dc000;
0115   } else {
0116     syscnt_base = (void *)0x306c0000;
0117   }
0118 
0119   freq = *(uint32_t *)(syscnt_base + SYSCNT_CNTFID(0));
0120 
0121   arm_cp15_set_counter_frequency(freq);
0122 
0123   *(uint32_t *)(syscnt_base + SYSCNT_CNTCR) =
0124     SYSCNT_CNTCR_ENABLE |
0125     SYSCNT_CNTCR_HDBG |
0126     SYSCNT_CNTCR_FCREQ(0);
0127 
0128   return freq;
0129 }
0130 
0131 void arm_generic_timer_get_config(
0132   uint32_t *frequency,
0133   uint32_t *irq
0134 )
0135 {
0136   const void *fdt;
0137   int node;
0138   int len;
0139   const uint32_t *val;
0140 
0141   fdt = bsp_fdt_get();
0142   node = fdt_path_offset(fdt, "/timer");
0143 
0144   val = fdt_getprop(fdt, node, "clock-frequency", &len);
0145   if (val != NULL && len >= 4) {
0146     *frequency = fdt32_to_cpu(val[0]);
0147   } else {
0148     /*
0149      * Normally clock-frequency would be provided by the boot loader. If it
0150      * didn't add one, we have to initialize the system counter ourself.
0151      */
0152     *frequency = imx_syscnt_enable_and_return_frequency(fdt);
0153   }
0154 
0155   /* FIXME: Figure out how Linux gets a proper IRQ number */
0156   *irq = imx_get_irq_of_node(fdt, node, 0) - 16;
0157 }
0158 
0159 uintptr_t imx_gic_dist_base;
0160 
0161 static void imx_find_gic(const void *fdt)
0162 {
0163   int node;
0164 
0165   node = fdt_path_offset(fdt, "/interrupt-controller");
0166   if (node < 0) {
0167     node = fdt_path_offset(fdt, "/soc/interrupt-controller");
0168   }
0169   imx_gic_dist_base = (uintptr_t) imx_get_reg_of_node(fdt, node);
0170 
0171 #if defined(RTEMS_SMP)
0172   /*
0173    * Secondary processors start with a disabled data cache and use the GIC to
0174    * deterine if they can continue the initialization, see
0175    * arm_gic_irq_initialize_secondary_cpu().
0176    */
0177   rtems_cache_flush_multiple_data_lines(
0178     &imx_gic_dist_base,
0179     sizeof(imx_gic_dist_base)
0180   );
0181 #endif
0182 }
0183 
0184 static void imx_ccm_enable_eth2_clk(void)
0185 {
0186   const void *fdt = bsp_fdt_get();
0187 
0188   if (imx_is_imx6(fdt)) {
0189     int node;
0190     volatile imx6ul_ccm_analog *ccm_analog = NULL;
0191 
0192     node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ul-anatop");
0193     if (node >= 0) {
0194         ccm_analog = imx_get_reg_of_node(fdt, node);
0195     }
0196     if (ccm_analog != NULL) {
0197         ccm_analog->pll_enet_set = IMX6UL_CCM_ANALOG_PLL_ENET_ENET2_125M_EN;
0198     }
0199   }
0200 }
0201 
0202 void bsp_start(void)
0203 {
0204   imx_find_gic(bsp_fdt_get());
0205   bsp_interrupt_initialize();
0206   rtems_cache_coherent_add_area(
0207     bsp_section_nocacheheap_begin,
0208     (uintptr_t) bsp_section_nocacheheap_size
0209   );
0210   imx_ccm_enable_eth2_clk();
0211 }