| /* Copyright (c) 2017, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| #include <drm/msm_drm_pp.h> |
| #include "sde_hw_catalog.h" |
| #include "sde_hw_util.h" |
| #include "sde_hw_mdss.h" |
| #include "sde_hw_lm.h" |
| #include "sde_ad4.h" |
| |
| #define IDLE_2_RUN(x) ((x) == (ad4_init | ad4_cfg | ad4_mode | ad4_input)) |
| #define MERGE_WIDTH_RIGHT 6 |
| #define MERGE_WIDTH_LEFT 5 |
| |
| enum ad4_ops_bitmask { |
| ad4_init = BIT(AD_INIT), |
| ad4_cfg = BIT(AD_CFG), |
| ad4_mode = BIT(AD_MODE), |
| ad4_input = BIT(AD_INPUT), |
| ad4_ops_max = BIT(31), |
| }; |
| |
| enum ad4_state { |
| ad4_state_idle, |
| ad4_state_run, |
| ad4_state_max, |
| }; |
| |
| typedef int (*ad4_prop_setup)(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *ad); |
| |
| static int ad4_mode_setup_common(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_init_setup_idle(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_cfg_setup_idle(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_input_setup_idle(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode); |
| static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); |
| static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); |
| static int ad4_input_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_suspend_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_params_check(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_assertive_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| static int ad4_backlight_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg); |
| |
| static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { |
| [ad4_state_idle][AD_MODE] = ad4_mode_setup_common, |
| [ad4_state_idle][AD_INIT] = ad4_init_setup_idle, |
| [ad4_state_idle][AD_CFG] = ad4_cfg_setup_idle, |
| [ad4_state_idle][AD_INPUT] = ad4_input_setup_idle, |
| [ad4_state_idle][AD_SUSPEND] = ad4_suspend_setup, |
| [ad4_state_idle][AD_ASSERTIVE] = ad4_assertive_setup, |
| [ad4_state_idle][AD_BACKLIGHT] = ad4_backlight_setup, |
| [ad4_state_run][AD_MODE] = ad4_mode_setup_common, |
| [ad4_state_run][AD_INIT] = ad4_init_setup, |
| [ad4_state_run][AD_CFG] = ad4_cfg_setup, |
| [ad4_state_run][AD_INPUT] = ad4_input_setup, |
| [ad4_state_run][AD_SUSPEND] = ad4_suspend_setup, |
| [ad4_state_run][AD_ASSERTIVE] = ad4_assertive_setup, |
| [ad4_state_run][AD_BACKLIGHT] = ad4_backlight_setup, |
| }; |
| |
| struct ad4_info { |
| enum ad4_state state; |
| u32 completed_ops_mask; |
| bool ad4_support; |
| enum ad4_modes cached_mode; |
| u32 cached_als; |
| }; |
| |
| static struct ad4_info info[DSPP_MAX] = { |
| [DSPP_0] = {ad4_state_idle, 0, true, AD4_OFF}, |
| [DSPP_1] = {ad4_state_idle, 0, true, AD4_OFF}, |
| [DSPP_2] = {ad4_state_max, 0, false, AD4_OFF}, |
| [DSPP_3] = {ad4_state_max, 0, false, AD4_OFF}, |
| }; |
| |
| void sde_setup_dspp_ad4(struct sde_hw_dspp *dspp, void *ad_cfg) |
| { |
| int ret = 0; |
| struct sde_ad_hw_cfg *cfg = ad_cfg; |
| |
| ret = ad4_params_check(dspp, ad_cfg); |
| if (ret) |
| return; |
| |
| ret = prop_set_func[info[dspp->idx].state][cfg->prop](dspp, ad_cfg); |
| if (ret) |
| DRM_ERROR("op failed %d ret %d\n", cfg->prop, ret); |
| } |
| |
| int sde_validate_dspp_ad4(struct sde_hw_dspp *dspp, u32 *prop) |
| { |
| |
| if (!dspp || !prop) { |
| DRM_ERROR("invalid params dspp %pK prop %pK\n", dspp, prop); |
| return -EINVAL; |
| } |
| |
| if (*prop >= AD_PROPMAX) { |
| DRM_ERROR("invalid prop set %d\n", *prop); |
| return -EINVAL; |
| } |
| |
| if (dspp->idx > DSPP_MAX || !info[dspp->idx].ad4_support) { |
| DRM_ERROR("ad4 not supported for dspp idx %d\n", dspp->idx); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static int ad4_params_check(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| struct sde_hw_mixer *hw_lm; |
| |
| if (!dspp || !cfg || !cfg->hw_cfg) { |
| DRM_ERROR("invalid dspp %pK cfg %pk hw_cfg %pK\n", |
| dspp, cfg, ((cfg) ? (cfg->hw_cfg) : NULL)); |
| return -EINVAL; |
| } |
| |
| if (!cfg->hw_cfg->mixer_info) { |
| DRM_ERROR("invalid mixed info\n"); |
| return -EINVAL; |
| } |
| |
| if (dspp->idx > DSPP_MAX || !info[dspp->idx].ad4_support) { |
| DRM_ERROR("ad4 not supported for dspp idx %d\n", dspp->idx); |
| return -EINVAL; |
| } |
| |
| if (cfg->prop >= AD_PROPMAX) { |
| DRM_ERROR("invalid prop set %d\n", cfg->prop); |
| return -EINVAL; |
| } |
| |
| if (info[dspp->idx].state >= ad4_state_max) { |
| DRM_ERROR("in max state for dspp idx %d\n", dspp->idx); |
| return -EINVAL; |
| } |
| |
| if (!prop_set_func[info[dspp->idx].state][cfg->prop]) { |
| DRM_ERROR("prop set not implemented for state %d prop %d\n", |
| info[dspp->idx].state, cfg->prop); |
| return -EINVAL; |
| } |
| |
| if (!cfg->hw_cfg->num_of_mixers || |
| cfg->hw_cfg->num_of_mixers > CRTC_DUAL_MIXERS) { |
| DRM_ERROR("invalid mixer cnt %d\n", |
| cfg->hw_cfg->num_of_mixers); |
| return -EINVAL; |
| } |
| hw_lm = cfg->hw_cfg->mixer_info; |
| |
| if (cfg->hw_cfg->num_of_mixers == 1 && |
| hw_lm->cfg.out_height != cfg->hw_cfg->displayv && |
| hw_lm->cfg.out_width != cfg->hw_cfg->displayh) { |
| DRM_ERROR("single_lm lmh %d lmw %d displayh %d displayw %d\n", |
| hw_lm->cfg.out_height, hw_lm->cfg.out_width, |
| cfg->hw_cfg->displayh, cfg->hw_cfg->displayv); |
| return -EINVAL; |
| } else if (hw_lm->cfg.out_height != cfg->hw_cfg->displayv && |
| hw_lm->cfg.out_width != (cfg->hw_cfg->displayh >> 1)) { |
| DRM_ERROR("dual_lm lmh %d lmw %d displayh %d displayw %d\n", |
| hw_lm->cfg.out_height, hw_lm->cfg.out_width, |
| cfg->hw_cfg->displayh, cfg->hw_cfg->displayv); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode) |
| { |
| u32 blk_offset; |
| |
| blk_offset = 0x04; |
| if (mode == AD4_OFF) { |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| 0x101); |
| info[dspp->idx].state = ad4_state_idle; |
| info[dspp->idx].completed_ops_mask = 0; |
| } else { |
| info[dspp->idx].state = ad4_state_run; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| 0); |
| } |
| |
| return 0; |
| } |
| |
| static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) |
| { |
| u32 frame_start, frame_end, proc_start, proc_end; |
| struct sde_hw_mixer *hw_lm; |
| u32 blk_offset, tile_ctl, val, i; |
| u32 off1, off2, off3, off4, off5, off6; |
| struct drm_msm_ad4_init *init; |
| |
| if (!cfg->hw_cfg->payload) { |
| info[dspp->idx].completed_ops_mask &= ~ad4_init; |
| return 0; |
| } |
| |
| if (cfg->hw_cfg->len != sizeof(struct drm_msm_ad4_init)) { |
| DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", |
| sizeof(struct drm_msm_ad4_init), cfg->hw_cfg->len, |
| cfg->hw_cfg->payload); |
| return -EINVAL; |
| } |
| |
| hw_lm = cfg->hw_cfg->mixer_info; |
| if (cfg->hw_cfg->num_of_mixers == 1) { |
| frame_start = 0; |
| frame_end = 0xffff; |
| proc_start = 0; |
| proc_end = 0xffff; |
| tile_ctl = 0; |
| } else { |
| tile_ctl = 0x5; |
| if (hw_lm->cfg.right_mixer) { |
| frame_start = (cfg->hw_cfg->displayh >> 1) - |
| MERGE_WIDTH_RIGHT; |
| frame_end = cfg->hw_cfg->displayh - 1; |
| proc_start = (cfg->hw_cfg->displayh >> 1); |
| proc_end = frame_end; |
| tile_ctl |= 0x10; |
| } else { |
| frame_start = 0; |
| frame_end = (cfg->hw_cfg->displayh >> 1) + |
| MERGE_WIDTH_LEFT; |
| proc_start = 0; |
| proc_end = (cfg->hw_cfg->displayh >> 1) - 1; |
| tile_ctl |= 0x10; |
| } |
| } |
| |
| init = cfg->hw_cfg->payload; |
| blk_offset = 8; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| init->init_param_009); |
| |
| blk_offset = 0xc; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| init->init_param_010); |
| |
| init->init_param_012 = cfg->hw_cfg->displayv & (BIT(17) - 1); |
| init->init_param_011 = cfg->hw_cfg->displayh & (BIT(17) - 1); |
| blk_offset = 0x10; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| ((init->init_param_011 << 16) | init->init_param_012)); |
| |
| blk_offset = 0x14; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| tile_ctl); |
| |
| blk_offset = 0x44; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| ((((init->init_param_013) & (BIT(17) - 1)) << 16) | |
| (init->init_param_014 & (BIT(17) - 1)))); |
| |
| blk_offset = 0x5c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_015 & (BIT(16) - 1))); |
| blk_offset = 0x60; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_016 & (BIT(8) - 1))); |
| blk_offset = 0x64; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_017 & (BIT(12) - 1))); |
| blk_offset = 0x68; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_018 & (BIT(12) - 1))); |
| blk_offset = 0x6c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_019 & (BIT(12) - 1))); |
| blk_offset = 0x70; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_020 & (BIT(16) - 1))); |
| blk_offset = 0x74; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_021 & (BIT(8) - 1))); |
| blk_offset = 0x78; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_022 & (BIT(8) - 1))); |
| blk_offset = 0x7c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_023 & (BIT(16) - 1))); |
| blk_offset = 0x80; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (((init->init_param_024 & (BIT(16) - 1)) << 16) | |
| ((init->init_param_025 & (BIT(16) - 1))))); |
| blk_offset = 0x84; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (((init->init_param_026 & (BIT(16) - 1)) << 16) | |
| ((init->init_param_027 & (BIT(16) - 1))))); |
| |
| blk_offset = 0x90; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_028 & (BIT(16) - 1))); |
| blk_offset = 0x94; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_029 & (BIT(16) - 1))); |
| |
| blk_offset = 0x98; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (((init->init_param_035 & (BIT(16) - 1)) << 16) | |
| ((init->init_param_030 & (BIT(16) - 1))))); |
| |
| blk_offset = 0x9c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (((init->init_param_032 & (BIT(16) - 1)) << 16) | |
| ((init->init_param_031 & (BIT(16) - 1))))); |
| blk_offset = 0xa0; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (((init->init_param_034 & (BIT(16) - 1)) << 16) | |
| ((init->init_param_033 & (BIT(16) - 1))))); |
| |
| blk_offset = 0xb4; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_036 & (BIT(8) - 1))); |
| blk_offset = 0xcc; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_037 & (BIT(8) - 1))); |
| blk_offset = 0xc0; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_038 & (BIT(8) - 1))); |
| blk_offset = 0xd8; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_039 & (BIT(8) - 1))); |
| |
| blk_offset = 0xe8; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_040 & (BIT(16) - 1))); |
| |
| blk_offset = 0xf4; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_041 & (BIT(8) - 1))); |
| |
| blk_offset = 0x100; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_042 & (BIT(16) - 1))); |
| |
| blk_offset = 0x10c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_043 & (BIT(8) - 1))); |
| |
| blk_offset = 0x120; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_044 & (BIT(16) - 1))); |
| blk_offset = 0x124; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_045 & (BIT(16) - 1))); |
| |
| blk_offset = 0x128; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_046 & (BIT(1) - 1))); |
| blk_offset = 0x12c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_047 & (BIT(8) - 1))); |
| |
| blk_offset = 0x13c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_048 & (BIT(5) - 1))); |
| blk_offset = 0x140; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_049 & (BIT(8) - 1))); |
| |
| blk_offset = 0x144; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_050 & (BIT(8) - 1))); |
| blk_offset = 0x148; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (((init->init_param_051 & (BIT(8) - 1)) << 8) | |
| ((init->init_param_052 & (BIT(8) - 1))))); |
| |
| blk_offset = 0x14c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_053 & (BIT(10) - 1))); |
| blk_offset = 0x150; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_054 & (BIT(10) - 1))); |
| blk_offset = 0x154; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_055 & (BIT(8) - 1))); |
| |
| blk_offset = 0x158; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_056 & (BIT(8) - 1))); |
| blk_offset = 0x164; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_057 & (BIT(8) - 1))); |
| blk_offset = 0x168; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_058 & (BIT(4) - 1))); |
| |
| blk_offset = 0x17c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (frame_start & (BIT(16) - 1))); |
| blk_offset = 0x180; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (frame_end & (BIT(16) - 1))); |
| blk_offset = 0x184; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (proc_start & (BIT(16) - 1))); |
| blk_offset = 0x188; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (proc_end & (BIT(16) - 1))); |
| |
| blk_offset = 0x18c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_059 & (BIT(4) - 1))); |
| |
| blk_offset = 0x190; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (((init->init_param_061 & (BIT(8) - 1)) << 8) | |
| ((init->init_param_060 & (BIT(8) - 1))))); |
| |
| blk_offset = 0x194; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_062 & (BIT(10) - 1))); |
| |
| blk_offset = 0x1a0; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_063 & (BIT(10) - 1))); |
| blk_offset = 0x1a4; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_064 & (BIT(10) - 1))); |
| blk_offset = 0x1a8; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_065 & (BIT(10) - 1))); |
| blk_offset = 0x1ac; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_066 & (BIT(8) - 1))); |
| blk_offset = 0x1b0; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_067 & (BIT(8) - 1))); |
| blk_offset = 0x1b4; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_068 & (BIT(6) - 1))); |
| |
| blk_offset = 0x460; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_069 & (BIT(16) - 1))); |
| blk_offset = 0x464; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_070 & (BIT(10) - 1))); |
| blk_offset = 0x468; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_071 & (BIT(10) - 1))); |
| blk_offset = 0x46c; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_072 & (BIT(10) - 1))); |
| blk_offset = 0x470; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_073 & (BIT(8) - 1))); |
| blk_offset = 0x474; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_074 & (BIT(10) - 1))); |
| blk_offset = 0x478; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (init->init_param_075 & (BIT(10) - 1))); |
| |
| off1 = 0x1c0; |
| off2 = 0x210; |
| off3 = 0x260; |
| off4 = 0x2b0; |
| off5 = 0x380; |
| off6 = 0x3d0; |
| for (i = 0; i < AD4_LUT_GRP0_SIZE - 1; i = i + 2) { |
| val = (init->init_param_001[i] & (BIT(16) - 1)); |
| val |= ((init->init_param_001[i + 1] & (BIT(16) - 1)) |
| << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off1, val); |
| off1 += 4; |
| |
| val = (init->init_param_002[i] & (BIT(16) - 1)); |
| val |= ((init->init_param_002[i + 1] & (BIT(16) - 1)) |
| << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off2, val); |
| off2 += 4; |
| |
| val = (init->init_param_003[i] & (BIT(16) - 1)); |
| val |= ((init->init_param_003[i + 1] & (BIT(16) - 1)) |
| << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off3, val); |
| off3 += 4; |
| |
| val = (init->init_param_004[i] & (BIT(16) - 1)); |
| val |= ((init->init_param_004[i + 1] & (BIT(16) - 1)) |
| << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off4, val); |
| off4 += 4; |
| |
| val = (init->init_param_007[i] & (BIT(16) - 1)); |
| val |= ((init->init_param_007[i + 1] & |
| (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off5, val); |
| off5 += 4; |
| |
| val = (init->init_param_008[i] & (BIT(12) - 1)); |
| val |= ((init->init_param_008[i + 1] & |
| (BIT(12) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off6, val); |
| off6 += 4; |
| } |
| /* write last index data */ |
| i = AD4_LUT_GRP0_SIZE - 1; |
| val = ((init->init_param_001[i] & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off1, val); |
| val = ((init->init_param_002[i] & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off2, val); |
| val = ((init->init_param_003[i] & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off3, val); |
| val = ((init->init_param_004[i] & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off4, val); |
| val = ((init->init_param_007[i] & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off5, val); |
| val = ((init->init_param_008[i] & (BIT(12) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off6, val); |
| |
| off1 = 0x300; |
| off2 = 0x340; |
| for (i = 0; i < AD4_LUT_GRP1_SIZE; i = i + 2) { |
| val = (init->init_param_005[i] & (BIT(16) - 1)); |
| val |= ((init->init_param_005[i + 1] & |
| (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off1, val); |
| off1 += 4; |
| |
| val = (init->init_param_006[i] & (BIT(16) - 1)); |
| val |= ((init->init_param_006[i + 1] & (BIT(16) - 1)) |
| << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off2, val); |
| off2 += 4; |
| } |
| |
| return 0; |
| } |
| |
| static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) |
| { |
| u32 blk_offset, val; |
| struct drm_msm_ad4_cfg *ad_cfg; |
| |
| if (!cfg->hw_cfg->payload) { |
| info[dspp->idx].completed_ops_mask &= ~ad4_cfg; |
| return 0; |
| } |
| |
| if (cfg->hw_cfg->len != sizeof(struct drm_msm_ad4_cfg)) { |
| DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", |
| sizeof(struct drm_msm_ad4_cfg), cfg->hw_cfg->len, |
| cfg->hw_cfg->payload); |
| return -EINVAL; |
| } |
| ad_cfg = cfg->hw_cfg->payload; |
| |
| blk_offset = 0x18; |
| val = (ad_cfg->cfg_param_002 & (BIT(16) - 1)); |
| val |= ((ad_cfg->cfg_param_001 & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_004 & (BIT(16) - 1)); |
| val |= ((ad_cfg->cfg_param_003 & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_005 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_006 & (BIT(7) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0x30; |
| val = (ad_cfg->cfg_param_007 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_008 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_009 & (BIT(10) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_010 & (BIT(12) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = ((ad_cfg->cfg_param_011 & (BIT(16) - 1)) << 16); |
| val |= (ad_cfg->cfg_param_012 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| |
| blk_offset = 0x88; |
| val = (ad_cfg->cfg_param_013 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_014 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0xa4; |
| val = (ad_cfg->cfg_param_015 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_016 & (BIT(10) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_017 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_018 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0xc4; |
| val = (ad_cfg->cfg_param_019 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_020 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0xb8; |
| val = (ad_cfg->cfg_param_021 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_022 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0xd0; |
| val = (ad_cfg->cfg_param_023 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_024 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0xdc; |
| val = (ad_cfg->cfg_param_025 & (BIT(16) - 1)); |
| val |= ((ad_cfg->cfg_param_026 & (BIT(16) - 1)) << 16); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_027 & (BIT(16) - 1)); |
| val |= ((ad_cfg->cfg_param_028 & (BIT(16) - 1)) << 16); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_029 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0xec; |
| val = (ad_cfg->cfg_param_030 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_031 & (BIT(12) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0xf8; |
| val = (ad_cfg->cfg_param_032 & (BIT(10) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_033 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0x104; |
| val = (ad_cfg->cfg_param_034 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_035 & (BIT(12) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0x110; |
| val = (ad_cfg->cfg_param_036 & (BIT(12) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_037 & (BIT(12) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_038 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_039 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0x134; |
| val = (ad_cfg->cfg_param_040 & (BIT(12) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_041 & (BIT(7) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0x15c; |
| val = (ad_cfg->cfg_param_042 & (BIT(10) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_043 & (BIT(10) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| blk_offset = 0x16c; |
| val = (ad_cfg->cfg_param_044 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_045 & (BIT(8) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| blk_offset += 4; |
| val = (ad_cfg->cfg_param_046 & (BIT(16) - 1)); |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); |
| |
| return 0; |
| } |
| |
| static int ad4_input_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| u64 *val, als; |
| u32 blk_offset; |
| |
| if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { |
| DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", |
| sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); |
| return -EINVAL; |
| } |
| |
| blk_offset = 0x28; |
| if (cfg->hw_cfg->payload) { |
| val = cfg->hw_cfg->payload; |
| } else { |
| als = 0; |
| val = &als; |
| } |
| info[dspp->idx].cached_als = *val; |
| info[dspp->idx].completed_ops_mask |= ad4_input; |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (*val & (BIT(16) - 1))); |
| |
| return 0; |
| } |
| |
| static int ad4_suspend_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| info[dspp->idx].state = ad4_state_idle; |
| info[dspp->idx].completed_ops_mask = 0; |
| return 0; |
| } |
| |
| static int ad4_mode_setup_common(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| |
| if (cfg->hw_cfg->len != sizeof(u64) || !cfg->hw_cfg->payload) { |
| DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", |
| sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); |
| return -EINVAL; |
| } |
| |
| info[dspp->idx].cached_mode = *((enum ad4_modes *) |
| (cfg->hw_cfg->payload)); |
| info[dspp->idx].completed_ops_mask |= ad4_mode; |
| |
| if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask) || |
| info[dspp->idx].cached_mode == AD4_OFF) |
| ad4_mode_setup(dspp, info[dspp->idx].cached_mode); |
| |
| return 0; |
| } |
| |
| static int ad4_init_setup_idle(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| int ret; |
| |
| if (!cfg->hw_cfg->payload) { |
| info[dspp->idx].completed_ops_mask &= ~ad4_init; |
| return 0; |
| } |
| |
| ret = ad4_init_setup(dspp, cfg); |
| if (ret) |
| return ret; |
| |
| info[dspp->idx].completed_ops_mask |= ad4_init; |
| |
| if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask)) |
| ad4_mode_setup(dspp, info[dspp->idx].cached_mode); |
| |
| return 0; |
| } |
| |
| static int ad4_cfg_setup_idle(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| int ret; |
| |
| if (!cfg->hw_cfg->payload) { |
| info[dspp->idx].completed_ops_mask &= ~ad4_cfg; |
| return 0; |
| } |
| |
| ret = ad4_cfg_setup(dspp, cfg); |
| if (ret) |
| return ret; |
| |
| info[dspp->idx].completed_ops_mask |= ad4_cfg; |
| if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask)) |
| ad4_mode_setup(dspp, info[dspp->idx].cached_mode); |
| return 0; |
| } |
| |
| static int ad4_input_setup_idle(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| int ret; |
| |
| ret = ad4_input_setup(dspp, cfg); |
| if (ret) |
| return ret; |
| |
| info[dspp->idx].completed_ops_mask |= ad4_input; |
| if (IDLE_2_RUN(info[dspp->idx].completed_ops_mask)) |
| ad4_mode_setup(dspp, info[dspp->idx].cached_mode); |
| |
| return 0; |
| } |
| |
| static int ad4_assertive_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| u64 *val, assertive; |
| u32 blk_offset; |
| |
| if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { |
| DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", |
| sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); |
| return -EINVAL; |
| } |
| |
| blk_offset = 0x30; |
| if (cfg->hw_cfg->payload) { |
| val = cfg->hw_cfg->payload; |
| } else { |
| assertive = 0; |
| val = &assertive; |
| } |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (*val & (BIT(8) - 1))); |
| return 0; |
| } |
| |
| static int ad4_backlight_setup(struct sde_hw_dspp *dspp, |
| struct sde_ad_hw_cfg *cfg) |
| { |
| u64 *val, bl; |
| u32 blk_offset; |
| |
| if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { |
| DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", |
| sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); |
| return -EINVAL; |
| } |
| |
| blk_offset = 0x2c; |
| if (cfg->hw_cfg->payload) { |
| val = cfg->hw_cfg->payload; |
| } else { |
| bl = 0; |
| val = &bl; |
| } |
| |
| SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, |
| (*val & (BIT(16) - 1))); |
| return 0; |
| } |
| |
| void sde_read_intr_resp_ad4(struct sde_hw_dspp *dspp, u32 event, u32 *resp) |
| { |
| if (!dspp || !resp) { |
| DRM_ERROR("invalid params dspp %pK resp %pK\n", dspp, resp); |
| return; |
| } |
| |
| switch (event) { |
| case AD4_BACKLIGHT: |
| *resp = SDE_REG_READ(&dspp->hw, |
| dspp->cap->sblk->ad.base + 0x48); |
| break; |
| default: |
| break; |
| } |
| } |