dpu_hw_lm.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include "dpu_kms.h"
  13. #include "dpu_hw_catalog.h"
  14. #include "dpu_hwio.h"
  15. #include "dpu_hw_lm.h"
  16. #include "dpu_hw_mdss.h"
  17. #include "dpu_dbg.h"
  18. #include "dpu_kms.h"
  19. #define LM_OP_MODE 0x00
  20. #define LM_OUT_SIZE 0x04
  21. #define LM_BORDER_COLOR_0 0x08
  22. #define LM_BORDER_COLOR_1 0x010
  23. /* These register are offset to mixer base + stage base */
  24. #define LM_BLEND0_OP 0x00
  25. #define LM_BLEND0_CONST_ALPHA 0x04
  26. #define LM_FG_COLOR_FILL_COLOR_0 0x08
  27. #define LM_FG_COLOR_FILL_COLOR_1 0x0C
  28. #define LM_FG_COLOR_FILL_SIZE 0x10
  29. #define LM_FG_COLOR_FILL_XY 0x14
  30. #define LM_BLEND0_FG_ALPHA 0x04
  31. #define LM_BLEND0_BG_ALPHA 0x08
  32. static struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer,
  33. struct dpu_mdss_cfg *m,
  34. void __iomem *addr,
  35. struct dpu_hw_blk_reg_map *b)
  36. {
  37. int i;
  38. for (i = 0; i < m->mixer_count; i++) {
  39. if (mixer == m->mixer[i].id) {
  40. b->base_off = addr;
  41. b->blk_off = m->mixer[i].base;
  42. b->length = m->mixer[i].len;
  43. b->hwversion = m->hwversion;
  44. b->log_mask = DPU_DBG_MASK_LM;
  45. return &m->mixer[i];
  46. }
  47. }
  48. return ERR_PTR(-ENOMEM);
  49. }
  50. /**
  51. * _stage_offset(): returns the relative offset of the blend registers
  52. * for the stage to be setup
  53. * @c: mixer ctx contains the mixer to be programmed
  54. * @stage: stage index to setup
  55. */
  56. static inline int _stage_offset(struct dpu_hw_mixer *ctx, enum dpu_stage stage)
  57. {
  58. const struct dpu_lm_sub_blks *sblk = ctx->cap->sblk;
  59. int rc;
  60. if (stage == DPU_STAGE_BASE)
  61. rc = -EINVAL;
  62. else if (stage <= sblk->maxblendstages)
  63. rc = sblk->blendstage_base[stage - DPU_STAGE_0];
  64. else
  65. rc = -EINVAL;
  66. return rc;
  67. }
  68. static void dpu_hw_lm_setup_out(struct dpu_hw_mixer *ctx,
  69. struct dpu_hw_mixer_cfg *mixer)
  70. {
  71. struct dpu_hw_blk_reg_map *c = &ctx->hw;
  72. u32 outsize;
  73. u32 op_mode;
  74. op_mode = DPU_REG_READ(c, LM_OP_MODE);
  75. outsize = mixer->out_height << 16 | mixer->out_width;
  76. DPU_REG_WRITE(c, LM_OUT_SIZE, outsize);
  77. /* SPLIT_LEFT_RIGHT */
  78. if (mixer->right_mixer)
  79. op_mode |= BIT(31);
  80. else
  81. op_mode &= ~BIT(31);
  82. DPU_REG_WRITE(c, LM_OP_MODE, op_mode);
  83. }
  84. static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx,
  85. struct dpu_mdss_color *color,
  86. u8 border_en)
  87. {
  88. struct dpu_hw_blk_reg_map *c = &ctx->hw;
  89. if (border_en) {
  90. DPU_REG_WRITE(c, LM_BORDER_COLOR_0,
  91. (color->color_0 & 0xFFF) |
  92. ((color->color_1 & 0xFFF) << 0x10));
  93. DPU_REG_WRITE(c, LM_BORDER_COLOR_1,
  94. (color->color_2 & 0xFFF) |
  95. ((color->color_3 & 0xFFF) << 0x10));
  96. }
  97. }
  98. static void dpu_hw_lm_setup_blend_config_sdm845(struct dpu_hw_mixer *ctx,
  99. u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
  100. {
  101. struct dpu_hw_blk_reg_map *c = &ctx->hw;
  102. int stage_off;
  103. u32 const_alpha;
  104. if (stage == DPU_STAGE_BASE)
  105. return;
  106. stage_off = _stage_offset(ctx, stage);
  107. if (WARN_ON(stage_off < 0))
  108. return;
  109. const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16);
  110. DPU_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha);
  111. DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
  112. }
  113. static void dpu_hw_lm_setup_blend_config(struct dpu_hw_mixer *ctx,
  114. u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
  115. {
  116. struct dpu_hw_blk_reg_map *c = &ctx->hw;
  117. int stage_off;
  118. if (stage == DPU_STAGE_BASE)
  119. return;
  120. stage_off = _stage_offset(ctx, stage);
  121. if (WARN_ON(stage_off < 0))
  122. return;
  123. DPU_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha);
  124. DPU_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha);
  125. DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
  126. }
  127. static void dpu_hw_lm_setup_color3(struct dpu_hw_mixer *ctx,
  128. uint32_t mixer_op_mode)
  129. {
  130. struct dpu_hw_blk_reg_map *c = &ctx->hw;
  131. int op_mode;
  132. /* read the existing op_mode configuration */
  133. op_mode = DPU_REG_READ(c, LM_OP_MODE);
  134. op_mode = (op_mode & (BIT(31) | BIT(30))) | mixer_op_mode;
  135. DPU_REG_WRITE(c, LM_OP_MODE, op_mode);
  136. }
  137. static void dpu_hw_lm_gc(struct dpu_hw_mixer *mixer,
  138. void *cfg)
  139. {
  140. }
  141. static void _setup_mixer_ops(struct dpu_mdss_cfg *m,
  142. struct dpu_hw_lm_ops *ops,
  143. unsigned long features)
  144. {
  145. ops->setup_mixer_out = dpu_hw_lm_setup_out;
  146. if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion))
  147. ops->setup_blend_config = dpu_hw_lm_setup_blend_config_sdm845;
  148. else
  149. ops->setup_blend_config = dpu_hw_lm_setup_blend_config;
  150. ops->setup_alpha_out = dpu_hw_lm_setup_color3;
  151. ops->setup_border_color = dpu_hw_lm_setup_border_color;
  152. ops->setup_gc = dpu_hw_lm_gc;
  153. };
  154. static struct dpu_hw_blk_ops dpu_hw_ops = {
  155. .start = NULL,
  156. .stop = NULL,
  157. };
  158. struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx,
  159. void __iomem *addr,
  160. struct dpu_mdss_cfg *m)
  161. {
  162. struct dpu_hw_mixer *c;
  163. struct dpu_lm_cfg *cfg;
  164. int rc;
  165. c = kzalloc(sizeof(*c), GFP_KERNEL);
  166. if (!c)
  167. return ERR_PTR(-ENOMEM);
  168. cfg = _lm_offset(idx, m, addr, &c->hw);
  169. if (IS_ERR_OR_NULL(cfg)) {
  170. kfree(c);
  171. return ERR_PTR(-EINVAL);
  172. }
  173. /* Assign ops */
  174. c->idx = idx;
  175. c->cap = cfg;
  176. _setup_mixer_ops(m, &c->ops, c->cap->features);
  177. rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_LM, idx, &dpu_hw_ops);
  178. if (rc) {
  179. DPU_ERROR("failed to init hw blk %d\n", rc);
  180. goto blk_init_error;
  181. }
  182. return c;
  183. blk_init_error:
  184. kzfree(c);
  185. return ERR_PTR(rc);
  186. }
  187. void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm)
  188. {
  189. if (lm)
  190. dpu_hw_blk_destroy(&lm->base);
  191. kfree(lm);
  192. }