aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2018-02-22 17:04:56 -0500
committerTony Lindgren <tony@atomide.com>2018-02-28 19:32:09 -0500
commit8c87970543b17adfbd829ec1541c72a7da518acf (patch)
treea039c1e038902c3c527bec94275b27714950267c /arch/arm/mach-omap2/omap_hwmod.c
parenta885f0fe209f262efa2c1cac9278a5774e5f7a80 (diff)
ARM: OMAP2+: Add functions to allocate module data from device tree
We can have ti-sysc driver manage the interconnect target module via platform data callback functions to hwmod code. This allows initializing and idling the devices using dts data instead of the legacy static data for interconnect target modules. Let's add functions to configure the module sysconfig data with platform callbacks from ti-sysc driver. Cc: Paul Walmsley <paul@pwsan.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c309
1 files changed, 308 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 124f9af34a15..20895fcadbf5 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -145,6 +145,8 @@
145 145
146#include <linux/platform_data/ti-sysc.h> 146#include <linux/platform_data/ti-sysc.h>
147 147
148#include <dt-bindings/bus/ti-sysc.h>
149
148#include <asm/system_misc.h> 150#include <asm/system_misc.h>
149 151
150#include "clock.h" 152#include "clock.h"
@@ -2498,7 +2500,7 @@ static void __init _setup_postsetup(struct omap_hwmod *oh)
2498 * affects the IP block hardware, or system integration hardware 2500 * affects the IP block hardware, or system integration hardware
2499 * associated with the IP block. Returns 0. 2501 * associated with the IP block. Returns 0.
2500 */ 2502 */
2501static int __init _setup(struct omap_hwmod *oh, void *data) 2503static int _setup(struct omap_hwmod *oh, void *data)
2502{ 2504{
2503 if (oh->_state != _HWMOD_STATE_INITIALIZED) 2505 if (oh->_state != _HWMOD_STATE_INITIALIZED)
2504 return 0; 2506 return 0;
@@ -3061,6 +3063,311 @@ int __init omap_hwmod_setup_one(const char *oh_name)
3061} 3063}
3062 3064
3063/** 3065/**
3066 * omap_hwmod_init_regbits - init sysconfig specific register bits
3067 * @dev: struct device
3068 * @data: module data
3069 * @sysc_fields: new sysc configuration
3070 */
3071static int omap_hwmod_init_regbits(struct device *dev,
3072 const struct ti_sysc_module_data *data,
3073 struct sysc_regbits **sysc_fields)
3074{
3075 *sysc_fields = NULL;
3076
3077 switch (data->cap->type) {
3078 case TI_SYSC_OMAP2:
3079 case TI_SYSC_OMAP2_TIMER:
3080 *sysc_fields = &omap_hwmod_sysc_type1;
3081 break;
3082 case TI_SYSC_OMAP3_SHAM:
3083 *sysc_fields = &omap3_sham_sysc_fields;
3084 break;
3085 case TI_SYSC_OMAP3_AES:
3086 *sysc_fields = &omap3xxx_aes_sysc_fields;
3087 break;
3088 case TI_SYSC_OMAP4:
3089 case TI_SYSC_OMAP4_TIMER:
3090 *sysc_fields = &omap_hwmod_sysc_type2;
3091 break;
3092 case TI_SYSC_OMAP4_SIMPLE:
3093 *sysc_fields = &omap_hwmod_sysc_type3;
3094 break;
3095 case TI_SYSC_OMAP34XX_SR:
3096 *sysc_fields = &omap34xx_sr_sysc_fields;
3097 break;
3098 case TI_SYSC_OMAP36XX_SR:
3099 *sysc_fields = &omap36xx_sr_sysc_fields;
3100 break;
3101 case TI_SYSC_OMAP4_SR:
3102 *sysc_fields = &omap36xx_sr_sysc_fields;
3103 break;
3104 case TI_SYSC_OMAP4_MCASP:
3105 *sysc_fields = &omap_hwmod_sysc_type_mcasp;
3106 break;
3107 case TI_SYSC_OMAP4_USB_HOST_FS:
3108 *sysc_fields = &omap_hwmod_sysc_type_usb_host_fs;
3109 break;
3110 default:
3111 return -EINVAL;
3112 }
3113
3114 return 0;
3115}
3116
3117/**
3118 * omap_hwmod_init_reg_offs - initialize sysconfig register offsets
3119 * @dev: struct device
3120 * @data: module data
3121 * @rev_offs: revision register offset
3122 * @sysc_offs: sysc register offset
3123 * @syss_offs: syss register offset
3124 */
3125int omap_hwmod_init_reg_offs(struct device *dev,
3126 const struct ti_sysc_module_data *data,
3127 u32 *rev_offs, u32 *sysc_offs, u32 *syss_offs)
3128{
3129 *rev_offs = 0;
3130 *sysc_offs = 0;
3131 *syss_offs = 0;
3132
3133 if (data->offsets[SYSC_REVISION] > 0)
3134 *rev_offs = data->offsets[SYSC_REVISION];
3135
3136 if (data->offsets[SYSC_SYSCONFIG] > 0)
3137 *sysc_offs = data->offsets[SYSC_SYSCONFIG];
3138
3139 if (data->offsets[SYSC_SYSSTATUS] > 0)
3140 *syss_offs = data->offsets[SYSC_SYSSTATUS];
3141
3142 return 0;
3143}
3144
3145/**
3146 * omap_hwmod_init_sysc_flags - initialize sysconfig features
3147 * @dev: struct device
3148 * @data: module data
3149 * @sysc_flags: module configuration
3150 */
3151int omap_hwmod_init_sysc_flags(struct device *dev,
3152 const struct ti_sysc_module_data *data,
3153 u32 *sysc_flags)
3154{
3155 *sysc_flags = 0;
3156
3157 switch (data->cap->type) {
3158 case TI_SYSC_OMAP2:
3159 case TI_SYSC_OMAP2_TIMER:
3160 /* See SYSC_OMAP2_* in include/dt-bindings/bus/ti-sysc.h */
3161 if (data->cfg->sysc_val & SYSC_OMAP2_CLOCKACTIVITY)
3162 *sysc_flags |= SYSC_HAS_CLOCKACTIVITY;
3163 if (data->cfg->sysc_val & SYSC_OMAP2_EMUFREE)
3164 *sysc_flags |= SYSC_HAS_EMUFREE;
3165 if (data->cfg->sysc_val & SYSC_OMAP2_ENAWAKEUP)
3166 *sysc_flags |= SYSC_HAS_ENAWAKEUP;
3167 if (data->cfg->sysc_val & SYSC_OMAP2_SOFTRESET)
3168 *sysc_flags |= SYSC_HAS_SOFTRESET;
3169 if (data->cfg->sysc_val & SYSC_OMAP2_AUTOIDLE)
3170 *sysc_flags |= SYSC_HAS_AUTOIDLE;
3171 break;
3172 case TI_SYSC_OMAP4:
3173 case TI_SYSC_OMAP4_TIMER:
3174 /* See SYSC_OMAP4_* in include/dt-bindings/bus/ti-sysc.h */
3175 if (data->cfg->sysc_val & SYSC_OMAP4_DMADISABLE)
3176 *sysc_flags |= SYSC_HAS_DMADISABLE;
3177 if (data->cfg->sysc_val & SYSC_OMAP4_FREEEMU)
3178 *sysc_flags |= SYSC_HAS_EMUFREE;
3179 if (data->cfg->sysc_val & SYSC_OMAP4_SOFTRESET)
3180 *sysc_flags |= SYSC_HAS_SOFTRESET;
3181 break;
3182 case TI_SYSC_OMAP34XX_SR:
3183 case TI_SYSC_OMAP36XX_SR:
3184 /* See SYSC_OMAP3_SR_* in include/dt-bindings/bus/ti-sysc.h */
3185 if (data->cfg->sysc_val & SYSC_OMAP3_SR_ENAWAKEUP)
3186 *sysc_flags |= SYSC_HAS_ENAWAKEUP;
3187 break;
3188 default:
3189 if (data->cap->regbits->emufree_shift >= 0)
3190 *sysc_flags |= SYSC_HAS_EMUFREE;
3191 if (data->cap->regbits->enwkup_shift >= 0)
3192 *sysc_flags |= SYSC_HAS_ENAWAKEUP;
3193 if (data->cap->regbits->srst_shift >= 0)
3194 *sysc_flags |= SYSC_HAS_SOFTRESET;
3195 if (data->cap->regbits->autoidle_shift >= 0)
3196 *sysc_flags |= SYSC_HAS_AUTOIDLE;
3197 break;
3198 }
3199
3200 if (data->cap->regbits->midle_shift >= 0 &&
3201 data->cfg->midlemodes)
3202 *sysc_flags |= SYSC_HAS_MIDLEMODE;
3203
3204 if (data->cap->regbits->sidle_shift >= 0 &&
3205 data->cfg->sidlemodes)
3206 *sysc_flags |= SYSC_HAS_SIDLEMODE;
3207
3208 if (data->cfg->quirks & SYSC_QUIRK_UNCACHED)
3209 *sysc_flags |= SYSC_NO_CACHE;
3210 if (data->cfg->quirks & SYSC_QUIRK_RESET_STATUS)
3211 *sysc_flags |= SYSC_HAS_RESET_STATUS;
3212
3213 if (data->cfg->syss_mask & 1)
3214 *sysc_flags |= SYSS_HAS_RESET_STATUS;
3215
3216 return 0;
3217}
3218
3219/**
3220 * omap_hwmod_init_idlemodes - initialize module idle modes
3221 * @dev: struct device
3222 * @data: module data
3223 * @idlemodes: module supported idle modes
3224 */
3225int omap_hwmod_init_idlemodes(struct device *dev,
3226 const struct ti_sysc_module_data *data,
3227 u32 *idlemodes)
3228{
3229 *idlemodes = 0;
3230
3231 if (data->cfg->midlemodes & BIT(SYSC_IDLE_FORCE))
3232 *idlemodes |= MSTANDBY_FORCE;
3233 if (data->cfg->midlemodes & BIT(SYSC_IDLE_NO))
3234 *idlemodes |= MSTANDBY_NO;
3235 if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART))
3236 *idlemodes |= MSTANDBY_SMART;
3237 if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART_WKUP))
3238 *idlemodes |= MSTANDBY_SMART_WKUP;
3239
3240 if (data->cfg->sidlemodes & BIT(SYSC_IDLE_FORCE))
3241 *idlemodes |= SIDLE_FORCE;
3242 if (data->cfg->sidlemodes & BIT(SYSC_IDLE_NO))
3243 *idlemodes |= SIDLE_NO;
3244 if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART))
3245 *idlemodes |= SIDLE_SMART;
3246 if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART_WKUP))
3247 *idlemodes |= SIDLE_SMART_WKUP;
3248
3249 return 0;
3250}
3251
3252/**
3253 * omap_hwmod_allocate_module - allocate new module
3254 * @dev: struct device
3255 * @oh: module
3256 * @sysc_fields: sysc register bits
3257 * @rev_offs: revision register offset
3258 * @sysc_offs: sysconfig register offset
3259 * @syss_offs: sysstatus register offset
3260 * @sysc_flags: sysc specific flags
3261 * @idlemodes: sysc supported idlemodes
3262 *
3263 * Note that the allocations here cannot use devm as ti-sysc can rebind.
3264 */
3265int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
3266 const struct ti_sysc_module_data *data,
3267 struct sysc_regbits *sysc_fields,
3268 u32 rev_offs, u32 sysc_offs, u32 syss_offs,
3269 u32 sysc_flags, u32 idlemodes)
3270{
3271 struct omap_hwmod_class_sysconfig *sysc;
3272 struct omap_hwmod_class *class;
3273 void __iomem *regs = NULL;
3274 unsigned long flags;
3275
3276 sysc = kzalloc(sizeof(*sysc), GFP_KERNEL);
3277 if (!sysc)
3278 return -ENOMEM;
3279
3280 sysc->sysc_fields = sysc_fields;
3281 sysc->rev_offs = rev_offs;
3282 sysc->sysc_offs = sysc_offs;
3283 sysc->syss_offs = syss_offs;
3284 sysc->sysc_flags = sysc_flags;
3285 sysc->idlemodes = idlemodes;
3286 sysc->srst_udelay = data->cfg->srst_udelay;
3287
3288 if (!oh->_mpu_rt_va) {
3289 regs = ioremap(data->module_pa,
3290 data->module_size);
3291 if (!regs)
3292 return -ENOMEM;
3293 }
3294
3295 /*
3296 * We need new oh->class as the other devices in the same class
3297 * may not yet have ioremapped their registers.
3298 */
3299 class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
3300 if (!class)
3301 return -ENOMEM;
3302
3303 class->sysc = sysc;
3304
3305 spin_lock_irqsave(&oh->_lock, flags);
3306 if (regs)
3307 oh->_mpu_rt_va = regs;
3308 oh->class = class;
3309 oh->_state = _HWMOD_STATE_INITIALIZED;
3310 _setup(oh, NULL);
3311 spin_unlock_irqrestore(&oh->_lock, flags);
3312
3313 return 0;
3314}
3315
3316/**
3317 * omap_hwmod_init_module - initialize new module
3318 * @dev: struct device
3319 * @data: module data
3320 * @cookie: cookie for the caller to use for later calls
3321 */
3322int omap_hwmod_init_module(struct device *dev,
3323 const struct ti_sysc_module_data *data,
3324 struct ti_sysc_cookie *cookie)
3325{
3326 struct omap_hwmod *oh;
3327 struct sysc_regbits *sysc_fields;
3328 u32 rev_offs, sysc_offs, syss_offs, sysc_flags, idlemodes;
3329 int error;
3330
3331 if (!dev || !data)
3332 return -EINVAL;
3333
3334 oh = _lookup(data->name);
3335 if (!oh)
3336 return -ENODEV;
3337
3338 cookie->data = oh;
3339
3340 error = omap_hwmod_init_regbits(dev, data, &sysc_fields);
3341 if (error)
3342 return error;
3343
3344 error = omap_hwmod_init_reg_offs(dev, data, &rev_offs,
3345 &sysc_offs, &syss_offs);
3346 if (error)
3347 return error;
3348
3349 error = omap_hwmod_init_sysc_flags(dev, data, &sysc_flags);
3350 if (error)
3351 return error;
3352
3353 error = omap_hwmod_init_idlemodes(dev, data, &idlemodes);
3354 if (error)
3355 return error;
3356
3357 if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
3358 oh->flags |= HWMOD_INIT_NO_IDLE;
3359 if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
3360 oh->flags |= HWMOD_INIT_NO_RESET;
3361
3362 if (oh->class->sysc)
3363 return 0;
3364
3365 return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
3366 rev_offs, sysc_offs, syss_offs,
3367 sysc_flags, idlemodes);
3368}
3369
3370/**
3064 * omap_hwmod_setup_earlycon_flags - set up flags for early console 3371 * omap_hwmod_setup_earlycon_flags - set up flags for early console
3065 * 3372 *
3066 * Enable DEBUG_OMAPUART_FLAGS for uart hwmod that is being used as 3373 * Enable DEBUG_OMAPUART_FLAGS for uart hwmod that is being used as