root/arch/arm/mach-omap2/cm_common.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. omap2_set_globals_cm
  2. cm_split_idlest_reg
  3. omap_cm_wait_module_ready
  4. omap_cm_wait_module_idle
  5. omap_cm_module_enable
  6. omap_cm_module_disable
  7. omap_cm_xlate_clkctrl
  8. cm_register
  9. cm_unregister
  10. omap2_cm_base_init
  11. omap_cm_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * OMAP2+ common Clock Management (CM) IP block functions
   4  *
   5  * Copyright (C) 2012 Texas Instruments, Inc.
   6  * Paul Walmsley
   7  *
   8  * XXX This code should eventually be moved to a CM driver.
   9  */
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/init.h>
  13 #include <linux/errno.h>
  14 #include <linux/bug.h>
  15 #include <linux/of.h>
  16 #include <linux/of_address.h>
  17 
  18 #include "cm2xxx.h"
  19 #include "cm3xxx.h"
  20 #include "cm33xx.h"
  21 #include "cm44xx.h"
  22 #include "clock.h"
  23 
  24 /*
  25  * cm_ll_data: function pointers to SoC-specific implementations of
  26  * common CM functions
  27  */
  28 static struct cm_ll_data null_cm_ll_data;
  29 static const struct cm_ll_data *cm_ll_data = &null_cm_ll_data;
  30 
  31 /* cm_base: base virtual address of the CM IP block */
  32 struct omap_domain_base cm_base;
  33 
  34 /* cm2_base: base virtual address of the CM2 IP block (OMAP44xx only) */
  35 struct omap_domain_base cm2_base;
  36 
  37 #define CM_NO_CLOCKS            0x1
  38 #define CM_SINGLE_INSTANCE      0x2
  39 
  40 /**
  41  * omap2_set_globals_cm - set the CM/CM2 base addresses (for early use)
  42  * @cm: CM base virtual address
  43  * @cm2: CM2 base virtual address (if present on the booted SoC)
  44  *
  45  * XXX Will be replaced when the PRM/CM drivers are completed.
  46  */
  47 void __init omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2)
  48 {
  49         cm_base.va = cm;
  50         cm2_base.va = cm2;
  51 }
  52 
  53 /**
  54  * cm_split_idlest_reg - split CM_IDLEST reg addr into its components
  55  * @idlest_reg: CM_IDLEST* virtual address
  56  * @prcm_inst: pointer to an s16 to return the PRCM instance offset
  57  * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
  58  *
  59  * Given an absolute CM_IDLEST register address @idlest_reg, passes
  60  * the PRCM instance offset and IDLEST register ID back to the caller
  61  * via the @prcm_inst and @idlest_reg_id.  Returns -EINVAL upon error,
  62  * or 0 upon success.  XXX This function is only needed until absolute
  63  * register addresses are removed from the OMAP struct clk records.
  64  */
  65 int cm_split_idlest_reg(struct clk_omap_reg *idlest_reg, s16 *prcm_inst,
  66                         u8 *idlest_reg_id)
  67 {
  68         int ret;
  69         if (!cm_ll_data->split_idlest_reg) {
  70                 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
  71                           __func__);
  72                 return -EINVAL;
  73         }
  74 
  75         ret = cm_ll_data->split_idlest_reg(idlest_reg, prcm_inst,
  76                                            idlest_reg_id);
  77         *prcm_inst -= cm_base.offset;
  78         return ret;
  79 }
  80 
  81 /**
  82  * omap_cm_wait_module_ready - wait for a module to leave idle or standby
  83  * @part: PRCM partition
  84  * @prcm_mod: PRCM module offset
  85  * @idlest_reg: CM_IDLESTx register
  86  * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
  87  *
  88  * Wait for the PRCM to indicate that the module identified by
  89  * (@prcm_mod, @idlest_id, @idlest_shift) is clocked.  Return 0 upon
  90  * success, -EBUSY if the module doesn't enable in time, or -EINVAL if
  91  * no per-SoC wait_module_ready() function pointer has been registered
  92  * or if the idlest register is unknown on the SoC.
  93  */
  94 int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg,
  95                               u8 idlest_shift)
  96 {
  97         if (!cm_ll_data->wait_module_ready) {
  98                 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
  99                           __func__);
 100                 return -EINVAL;
 101         }
 102 
 103         return cm_ll_data->wait_module_ready(part, prcm_mod, idlest_reg,
 104                                              idlest_shift);
 105 }
 106 
 107 /**
 108  * omap_cm_wait_module_idle - wait for a module to enter idle or standby
 109  * @part: PRCM partition
 110  * @prcm_mod: PRCM module offset
 111  * @idlest_reg: CM_IDLESTx register
 112  * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
 113  *
 114  * Wait for the PRCM to indicate that the module identified by
 115  * (@prcm_mod, @idlest_id, @idlest_shift) is no longer clocked.  Return
 116  * 0 upon success, -EBUSY if the module doesn't enable in time, or
 117  * -EINVAL if no per-SoC wait_module_idle() function pointer has been
 118  * registered or if the idlest register is unknown on the SoC.
 119  */
 120 int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg,
 121                              u8 idlest_shift)
 122 {
 123         if (!cm_ll_data->wait_module_idle) {
 124                 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
 125                           __func__);
 126                 return -EINVAL;
 127         }
 128 
 129         return cm_ll_data->wait_module_idle(part, prcm_mod, idlest_reg,
 130                                             idlest_shift);
 131 }
 132 
 133 /**
 134  * omap_cm_module_enable - enable a module
 135  * @mode: target mode for the module
 136  * @part: PRCM partition
 137  * @inst: PRCM instance
 138  * @clkctrl_offs: CM_CLKCTRL register offset for the module
 139  *
 140  * Enables clocks for a module identified by (@part, @inst, @clkctrl_offs)
 141  * making its IO space accessible. Return 0 upon success, -EINVAL if no
 142  * per-SoC module_enable() function pointer has been registered.
 143  */
 144 int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs)
 145 {
 146         if (!cm_ll_data->module_enable) {
 147                 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
 148                           __func__);
 149                 return -EINVAL;
 150         }
 151 
 152         cm_ll_data->module_enable(mode, part, inst, clkctrl_offs);
 153         return 0;
 154 }
 155 
 156 /**
 157  * omap_cm_module_disable - disable a module
 158  * @part: PRCM partition
 159  * @inst: PRCM instance
 160  * @clkctrl_offs: CM_CLKCTRL register offset for the module
 161  *
 162  * Disables clocks for a module identified by (@part, @inst, @clkctrl_offs)
 163  * makings its IO space inaccessible. Return 0 upon success, -EINVAL if
 164  * no per-SoC module_disable() function pointer has been registered.
 165  */
 166 int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
 167 {
 168         if (!cm_ll_data->module_disable) {
 169                 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
 170                           __func__);
 171                 return -EINVAL;
 172         }
 173 
 174         cm_ll_data->module_disable(part, inst, clkctrl_offs);
 175         return 0;
 176 }
 177 
 178 u32 omap_cm_xlate_clkctrl(u8 part, u16 inst, u16 clkctrl_offs)
 179 {
 180         if (!cm_ll_data->xlate_clkctrl) {
 181                 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
 182                           __func__);
 183                 return 0;
 184         }
 185         return cm_ll_data->xlate_clkctrl(part, inst, clkctrl_offs);
 186 }
 187 
 188 /**
 189  * cm_register - register per-SoC low-level data with the CM
 190  * @cld: low-level per-SoC OMAP CM data & function pointers to register
 191  *
 192  * Register per-SoC low-level OMAP CM data and function pointers with
 193  * the OMAP CM common interface.  The caller must keep the data
 194  * pointed to by @cld valid until it calls cm_unregister() and
 195  * it returns successfully.  Returns 0 upon success, -EINVAL if @cld
 196  * is NULL, or -EEXIST if cm_register() has already been called
 197  * without an intervening cm_unregister().
 198  */
 199 int cm_register(const struct cm_ll_data *cld)
 200 {
 201         if (!cld)
 202                 return -EINVAL;
 203 
 204         if (cm_ll_data != &null_cm_ll_data)
 205                 return -EEXIST;
 206 
 207         cm_ll_data = cld;
 208 
 209         return 0;
 210 }
 211 
 212 /**
 213  * cm_unregister - unregister per-SoC low-level data & function pointers
 214  * @cld: low-level per-SoC OMAP CM data & function pointers to unregister
 215  *
 216  * Unregister per-SoC low-level OMAP CM data and function pointers
 217  * that were previously registered with cm_register().  The
 218  * caller may not destroy any of the data pointed to by @cld until
 219  * this function returns successfully.  Returns 0 upon success, or
 220  * -EINVAL if @cld is NULL or if @cld does not match the struct
 221  * cm_ll_data * previously registered by cm_register().
 222  */
 223 int cm_unregister(const struct cm_ll_data *cld)
 224 {
 225         if (!cld || cm_ll_data != cld)
 226                 return -EINVAL;
 227 
 228         cm_ll_data = &null_cm_ll_data;
 229 
 230         return 0;
 231 }
 232 
 233 #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
 234         defined(CONFIG_SOC_DRA7XX)
 235 static struct omap_prcm_init_data cm_data __initdata = {
 236         .index = TI_CLKM_CM,
 237         .init = omap4_cm_init,
 238 };
 239 
 240 static struct omap_prcm_init_data cm2_data __initdata = {
 241         .index = TI_CLKM_CM2,
 242         .init = omap4_cm_init,
 243 };
 244 #endif
 245 
 246 #ifdef CONFIG_ARCH_OMAP2
 247 static struct omap_prcm_init_data omap2_prcm_data __initdata = {
 248         .index = TI_CLKM_CM,
 249         .init = omap2xxx_cm_init,
 250         .flags = CM_NO_CLOCKS | CM_SINGLE_INSTANCE,
 251 };
 252 #endif
 253 
 254 #ifdef CONFIG_ARCH_OMAP3
 255 static struct omap_prcm_init_data omap3_cm_data __initdata = {
 256         .index = TI_CLKM_CM,
 257         .init = omap3xxx_cm_init,
 258         .flags = CM_SINGLE_INSTANCE,
 259 
 260         /*
 261          * IVA2 offset is a negative value, must offset the cm_base address
 262          * by this to get it to positive side on the iomap
 263          */
 264         .offset = -OMAP3430_IVA2_MOD,
 265 };
 266 #endif
 267 
 268 #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_TI81XX)
 269 static struct omap_prcm_init_data am3_prcm_data __initdata = {
 270         .index = TI_CLKM_CM,
 271         .flags = CM_NO_CLOCKS | CM_SINGLE_INSTANCE,
 272         .init = am33xx_cm_init,
 273 };
 274 #endif
 275 
 276 #ifdef CONFIG_SOC_AM43XX
 277 static struct omap_prcm_init_data am4_prcm_data __initdata = {
 278         .index = TI_CLKM_CM,
 279         .flags = CM_NO_CLOCKS | CM_SINGLE_INSTANCE,
 280         .init = omap4_cm_init,
 281 };
 282 #endif
 283 
 284 static const struct of_device_id omap_cm_dt_match_table[] __initconst = {
 285 #ifdef CONFIG_ARCH_OMAP2
 286         { .compatible = "ti,omap2-prcm", .data = &omap2_prcm_data },
 287 #endif
 288 #ifdef CONFIG_ARCH_OMAP3
 289         { .compatible = "ti,omap3-cm", .data = &omap3_cm_data },
 290 #endif
 291 #ifdef CONFIG_ARCH_OMAP4
 292         { .compatible = "ti,omap4-cm1", .data = &cm_data },
 293         { .compatible = "ti,omap4-cm2", .data = &cm2_data },
 294 #endif
 295 #ifdef CONFIG_SOC_OMAP5
 296         { .compatible = "ti,omap5-cm-core-aon", .data = &cm_data },
 297         { .compatible = "ti,omap5-cm-core", .data = &cm2_data },
 298 #endif
 299 #ifdef CONFIG_SOC_DRA7XX
 300         { .compatible = "ti,dra7-cm-core-aon", .data = &cm_data },
 301         { .compatible = "ti,dra7-cm-core", .data = &cm2_data },
 302 #endif
 303 #ifdef CONFIG_SOC_AM33XX
 304         { .compatible = "ti,am3-prcm", .data = &am3_prcm_data },
 305 #endif
 306 #ifdef CONFIG_SOC_AM43XX
 307         { .compatible = "ti,am4-prcm", .data = &am4_prcm_data },
 308 #endif
 309 #ifdef CONFIG_SOC_TI81XX
 310         { .compatible = "ti,dm814-prcm", .data = &am3_prcm_data },
 311         { .compatible = "ti,dm816-prcm", .data = &am3_prcm_data },
 312 #endif
 313         { }
 314 };
 315 
 316 /**
 317  * omap2_cm_base_init - initialize iomappings for the CM drivers
 318  *
 319  * Detects and initializes the iomappings for the CM driver, based
 320  * on the DT data. Returns 0 in success, negative error value
 321  * otherwise.
 322  */
 323 int __init omap2_cm_base_init(void)
 324 {
 325         struct device_node *np;
 326         const struct of_device_id *match;
 327         struct omap_prcm_init_data *data;
 328         struct resource res;
 329         int ret;
 330         struct omap_domain_base *mem = NULL;
 331 
 332         for_each_matching_node_and_match(np, omap_cm_dt_match_table, &match) {
 333                 data = (struct omap_prcm_init_data *)match->data;
 334 
 335                 ret = of_address_to_resource(np, 0, &res);
 336                 if (ret)
 337                         return ret;
 338 
 339                 if (data->index == TI_CLKM_CM)
 340                         mem = &cm_base;
 341 
 342                 if (data->index == TI_CLKM_CM2)
 343                         mem = &cm2_base;
 344 
 345                 data->mem = ioremap(res.start, resource_size(&res));
 346 
 347                 if (mem) {
 348                         mem->pa = res.start + data->offset;
 349                         mem->va = data->mem + data->offset;
 350                         mem->offset = data->offset;
 351                 }
 352 
 353                 data->np = np;
 354 
 355                 if (data->init && (data->flags & CM_SINGLE_INSTANCE ||
 356                                    (cm_base.va && cm2_base.va)))
 357                         data->init(data);
 358         }
 359 
 360         return 0;
 361 }
 362 
 363 /**
 364  * omap_cm_init - low level init for the CM drivers
 365  *
 366  * Initializes the low level clock infrastructure for CM drivers.
 367  * Returns 0 in success, negative error value in failure.
 368  */
 369 int __init omap_cm_init(void)
 370 {
 371         struct device_node *np;
 372         const struct of_device_id *match;
 373         const struct omap_prcm_init_data *data;
 374         int ret;
 375 
 376         for_each_matching_node_and_match(np, omap_cm_dt_match_table, &match) {
 377                 data = match->data;
 378 
 379                 if (data->flags & CM_NO_CLOCKS)
 380                         continue;
 381 
 382                 ret = omap2_clk_provider_init(np, data->index, NULL, data->mem);
 383                 if (ret)
 384                         return ret;
 385         }
 386 
 387         return 0;
 388 }

/* [<][>][^][v][top][bottom][index][help] */