root/drivers/gpu/drm/sun4i/sun4i_frontend.c

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

DEFINITIONS

This source file includes following definitions.
  1. sun4i_frontend_scaler_init
  2. sun4i_frontend_init
  3. sun4i_frontend_exit
  4. sun4i_frontend_format_chroma_requires_swap
  5. sun4i_frontend_format_supports_tiling
  6. sun4i_frontend_update_buffer
  7. sun4i_frontend_drm_format_to_input_fmt
  8. sun4i_frontend_drm_format_to_input_mode
  9. sun4i_frontend_drm_format_to_input_sequence
  10. sun4i_frontend_drm_format_to_output_fmt
  11. sun4i_frontend_format_is_supported
  12. sun4i_frontend_update_formats
  13. sun4i_frontend_update_coord
  14. sun4i_frontend_enable
  15. sun4i_frontend_bind
  16. sun4i_frontend_unbind
  17. sun4i_frontend_probe
  18. sun4i_frontend_remove
  19. sun4i_frontend_runtime_resume
  20. sun4i_frontend_runtime_suspend

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright (C) 2017 Free Electrons
   4  * Maxime Ripard <maxime.ripard@free-electrons.com>
   5  */
   6 
   7 #include <linux/clk.h>
   8 #include <linux/component.h>
   9 #include <linux/module.h>
  10 #include <linux/of_device.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/pm_runtime.h>
  13 #include <linux/regmap.h>
  14 #include <linux/reset.h>
  15 
  16 #include <drm/drm_device.h>
  17 #include <drm/drm_fb_cma_helper.h>
  18 #include <drm/drm_fourcc.h>
  19 #include <drm/drm_framebuffer.h>
  20 #include <drm/drm_gem_cma_helper.h>
  21 #include <drm/drm_plane.h>
  22 
  23 #include "sun4i_drv.h"
  24 #include "sun4i_frontend.h"
  25 
  26 static const u32 sun4i_frontend_vert_coef[32] = {
  27         0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
  28         0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
  29         0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
  30         0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
  31         0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
  32         0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
  33         0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
  34         0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
  35 };
  36 
  37 static const u32 sun4i_frontend_horz_coef[64] = {
  38         0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
  39         0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
  40         0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
  41         0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
  42         0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
  43         0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
  44         0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
  45         0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
  46         0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
  47         0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
  48         0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
  49         0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
  50         0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
  51         0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
  52         0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
  53         0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
  54 };
  55 
  56 /*
  57  * These coefficients are taken from the A33 BSP from Allwinner.
  58  *
  59  * The first three values of each row are coded as 13-bit signed fixed-point
  60  * numbers, with 10 bits for the fractional part. The fourth value is a
  61  * constant coded as a 14-bit signed fixed-point number with 4 bits for the
  62  * fractional part.
  63  *
  64  * The values in table order give the following colorspace translation:
  65  * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
  66  * R = 1.164 * Y + 1.596 * V - 222
  67  * B = 1.164 * Y + 2.018 * U + 276
  68  *
  69  * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255],
  70  * following the BT601 spec.
  71  */
  72 const u32 sunxi_bt601_yuv2rgb_coef[12] = {
  73         0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
  74         0x000004a7, 0x00000000, 0x00000662, 0x00003211,
  75         0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
  76 };
  77 EXPORT_SYMBOL(sunxi_bt601_yuv2rgb_coef);
  78 
  79 static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
  80 {
  81         int i;
  82 
  83         if (frontend->data->has_coef_access_ctrl)
  84                 regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
  85                                   SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL,
  86                                   SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL);
  87 
  88         for (i = 0; i < 32; i++) {
  89                 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
  90                              sun4i_frontend_horz_coef[2 * i]);
  91                 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
  92                              sun4i_frontend_horz_coef[2 * i]);
  93                 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
  94                              sun4i_frontend_horz_coef[2 * i + 1]);
  95                 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
  96                              sun4i_frontend_horz_coef[2 * i + 1]);
  97                 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
  98                              sun4i_frontend_vert_coef[i]);
  99                 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
 100                              sun4i_frontend_vert_coef[i]);
 101         }
 102 
 103         if (frontend->data->has_coef_rdy)
 104                 regmap_write_bits(frontend->regs,
 105                                   SUN4I_FRONTEND_FRM_CTRL_REG,
 106                                   SUN4I_FRONTEND_FRM_CTRL_COEF_RDY,
 107                                   SUN4I_FRONTEND_FRM_CTRL_COEF_RDY);
 108 }
 109 
 110 int sun4i_frontend_init(struct sun4i_frontend *frontend)
 111 {
 112         return pm_runtime_get_sync(frontend->dev);
 113 }
 114 EXPORT_SYMBOL(sun4i_frontend_init);
 115 
 116 void sun4i_frontend_exit(struct sun4i_frontend *frontend)
 117 {
 118         pm_runtime_put(frontend->dev);
 119 }
 120 EXPORT_SYMBOL(sun4i_frontend_exit);
 121 
 122 static bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt)
 123 {
 124         switch (fmt) {
 125         case DRM_FORMAT_YVU411:
 126         case DRM_FORMAT_YVU420:
 127         case DRM_FORMAT_YVU422:
 128         case DRM_FORMAT_YVU444:
 129                 return true;
 130 
 131         default:
 132                 return false;
 133         }
 134 }
 135 
 136 static bool sun4i_frontend_format_supports_tiling(uint32_t fmt)
 137 {
 138         switch (fmt) {
 139         case DRM_FORMAT_NV12:
 140         case DRM_FORMAT_NV16:
 141         case DRM_FORMAT_NV21:
 142         case DRM_FORMAT_NV61:
 143         case DRM_FORMAT_YUV411:
 144         case DRM_FORMAT_YUV420:
 145         case DRM_FORMAT_YUV422:
 146         case DRM_FORMAT_YVU420:
 147         case DRM_FORMAT_YVU422:
 148         case DRM_FORMAT_YVU411:
 149                 return true;
 150 
 151         default:
 152                 return false;
 153         }
 154 }
 155 
 156 void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
 157                                   struct drm_plane *plane)
 158 {
 159         struct drm_plane_state *state = plane->state;
 160         struct drm_framebuffer *fb = state->fb;
 161         unsigned int strides[3] = {};
 162 
 163         dma_addr_t paddr;
 164         bool swap;
 165 
 166         if (fb->modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) {
 167                 unsigned int width = state->src_w >> 16;
 168                 unsigned int offset;
 169 
 170                 strides[0] = SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[0]);
 171 
 172                 /*
 173                  * The X1 offset is the offset to the bottom-right point in the
 174                  * end tile, which is the final pixel (at offset width - 1)
 175                  * within the end tile (with a 32-byte mask).
 176                  */
 177                 offset = (width - 1) & (32 - 1);
 178 
 179                 regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF0_REG,
 180                              SUN4I_FRONTEND_TB_OFF_X1(offset));
 181 
 182                 if (fb->format->num_planes > 1) {
 183                         strides[1] =
 184                                 SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[1]);
 185 
 186                         regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF1_REG,
 187                                      SUN4I_FRONTEND_TB_OFF_X1(offset));
 188                 }
 189 
 190                 if (fb->format->num_planes > 2) {
 191                         strides[2] =
 192                                 SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[2]);
 193 
 194                         regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF2_REG,
 195                                      SUN4I_FRONTEND_TB_OFF_X1(offset));
 196                 }
 197         } else {
 198                 strides[0] = fb->pitches[0];
 199 
 200                 if (fb->format->num_planes > 1)
 201                         strides[1] = fb->pitches[1];
 202 
 203                 if (fb->format->num_planes > 2)
 204                         strides[2] = fb->pitches[2];
 205         }
 206 
 207         /* Set the line width */
 208         DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
 209         regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
 210                      strides[0]);
 211 
 212         if (fb->format->num_planes > 1)
 213                 regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG,
 214                              strides[1]);
 215 
 216         if (fb->format->num_planes > 2)
 217                 regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG,
 218                              strides[2]);
 219 
 220         /* Some planar formats require chroma channel swapping by hand. */
 221         swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format);
 222 
 223         /* Set the physical address of the buffer in memory */
 224         paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
 225         paddr -= PHYS_OFFSET;
 226         DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &paddr);
 227         regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
 228 
 229         if (fb->format->num_planes > 1) {
 230                 paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1);
 231                 paddr -= PHYS_OFFSET;
 232                 DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr);
 233                 regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG,
 234                              paddr);
 235         }
 236 
 237         if (fb->format->num_planes > 2) {
 238                 paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2);
 239                 paddr -= PHYS_OFFSET;
 240                 DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr);
 241                 regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG,
 242                              paddr);
 243         }
 244 }
 245 EXPORT_SYMBOL(sun4i_frontend_update_buffer);
 246 
 247 static int
 248 sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format,
 249                                        u32 *val)
 250 {
 251         if (!format->is_yuv)
 252                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB;
 253         else if (drm_format_info_is_yuv_sampling_411(format))
 254                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411;
 255         else if (drm_format_info_is_yuv_sampling_420(format))
 256                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420;
 257         else if (drm_format_info_is_yuv_sampling_422(format))
 258                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422;
 259         else if (drm_format_info_is_yuv_sampling_444(format))
 260                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444;
 261         else
 262                 return -EINVAL;
 263 
 264         return 0;
 265 }
 266 
 267 static int
 268 sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format,
 269                                         uint64_t modifier, u32 *val)
 270 {
 271         bool tiled = (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED);
 272 
 273         switch (format->num_planes) {
 274         case 1:
 275                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED;
 276                 return 0;
 277 
 278         case 2:
 279                 *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR
 280                              : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR;
 281                 return 0;
 282 
 283         case 3:
 284                 *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR
 285                              : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR;
 286                 return 0;
 287 
 288         default:
 289                 return -EINVAL;
 290         }
 291 }
 292 
 293 static int
 294 sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format,
 295                                             u32 *val)
 296 {
 297         /* Planar formats have an explicit input sequence. */
 298         if (drm_format_info_is_yuv_planar(format)) {
 299                 *val = 0;
 300                 return 0;
 301         }
 302 
 303         switch (format->format) {
 304         case DRM_FORMAT_BGRX8888:
 305                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX;
 306                 return 0;
 307 
 308         case DRM_FORMAT_NV12:
 309                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
 310                 return 0;
 311 
 312         case DRM_FORMAT_NV16:
 313                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
 314                 return 0;
 315 
 316         case DRM_FORMAT_NV21:
 317                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
 318                 return 0;
 319 
 320         case DRM_FORMAT_NV61:
 321                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
 322                 return 0;
 323 
 324         case DRM_FORMAT_UYVY:
 325                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY;
 326                 return 0;
 327 
 328         case DRM_FORMAT_VYUY:
 329                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY;
 330                 return 0;
 331 
 332         case DRM_FORMAT_XRGB8888:
 333                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB;
 334                 return 0;
 335 
 336         case DRM_FORMAT_YUYV:
 337                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV;
 338                 return 0;
 339 
 340         case DRM_FORMAT_YVYU:
 341                 *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU;
 342                 return 0;
 343 
 344         default:
 345                 return -EINVAL;
 346         }
 347 }
 348 
 349 static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
 350 {
 351         switch (fmt) {
 352         case DRM_FORMAT_BGRX8888:
 353                 *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888;
 354                 return 0;
 355 
 356         case DRM_FORMAT_XRGB8888:
 357                 *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888;
 358                 return 0;
 359 
 360         default:
 361                 return -EINVAL;
 362         }
 363 }
 364 
 365 static const uint32_t sun4i_frontend_formats[] = {
 366         DRM_FORMAT_BGRX8888,
 367         DRM_FORMAT_NV12,
 368         DRM_FORMAT_NV16,
 369         DRM_FORMAT_NV21,
 370         DRM_FORMAT_NV61,
 371         DRM_FORMAT_UYVY,
 372         DRM_FORMAT_VYUY,
 373         DRM_FORMAT_XRGB8888,
 374         DRM_FORMAT_YUV411,
 375         DRM_FORMAT_YUV420,
 376         DRM_FORMAT_YUV422,
 377         DRM_FORMAT_YUV444,
 378         DRM_FORMAT_YUYV,
 379         DRM_FORMAT_YVU411,
 380         DRM_FORMAT_YVU420,
 381         DRM_FORMAT_YVU422,
 382         DRM_FORMAT_YVU444,
 383         DRM_FORMAT_YVYU,
 384 };
 385 
 386 bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier)
 387 {
 388         unsigned int i;
 389 
 390         if (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED)
 391                 return sun4i_frontend_format_supports_tiling(fmt);
 392         else if (modifier != DRM_FORMAT_MOD_LINEAR)
 393                 return false;
 394 
 395         for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++)
 396                 if (sun4i_frontend_formats[i] == fmt)
 397                         return true;
 398 
 399         return false;
 400 }
 401 EXPORT_SYMBOL(sun4i_frontend_format_is_supported);
 402 
 403 int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
 404                                   struct drm_plane *plane, uint32_t out_fmt)
 405 {
 406         struct drm_plane_state *state = plane->state;
 407         struct drm_framebuffer *fb = state->fb;
 408         const struct drm_format_info *format = fb->format;
 409         uint64_t modifier = fb->modifier;
 410         u32 out_fmt_val;
 411         u32 in_fmt_val, in_mod_val, in_ps_val;
 412         unsigned int i;
 413         u32 bypass;
 414         int ret;
 415 
 416         ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val);
 417         if (ret) {
 418                 DRM_DEBUG_DRIVER("Invalid input format\n");
 419                 return ret;
 420         }
 421 
 422         ret = sun4i_frontend_drm_format_to_input_mode(format, modifier,
 423                                                       &in_mod_val);
 424         if (ret) {
 425                 DRM_DEBUG_DRIVER("Invalid input mode\n");
 426                 return ret;
 427         }
 428 
 429         ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val);
 430         if (ret) {
 431                 DRM_DEBUG_DRIVER("Invalid pixel sequence\n");
 432                 return ret;
 433         }
 434 
 435         ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
 436         if (ret) {
 437                 DRM_DEBUG_DRIVER("Invalid output format\n");
 438                 return ret;
 439         }
 440 
 441         /*
 442          * I have no idea what this does exactly, but it seems to be
 443          * related to the scaler FIR filter phase parameters.
 444          */
 445         regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG,
 446                      frontend->data->ch_phase[0].horzphase);
 447         regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG,
 448                      frontend->data->ch_phase[1].horzphase);
 449         regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG,
 450                      frontend->data->ch_phase[0].vertphase[0]);
 451         regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG,
 452                      frontend->data->ch_phase[1].vertphase[0]);
 453         regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG,
 454                      frontend->data->ch_phase[0].vertphase[1]);
 455         regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG,
 456                      frontend->data->ch_phase[1].vertphase[1]);
 457 
 458         /*
 459          * Checking the input format is sufficient since we currently only
 460          * support RGB output formats to the backend. If YUV output formats
 461          * ever get supported, an YUV input and output would require bypassing
 462          * the CSC engine too.
 463          */
 464         if (format->is_yuv) {
 465                 /* Setup the CSC engine for YUV to RGB conversion. */
 466                 bypass = 0;
 467 
 468                 for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
 469                         regmap_write(frontend->regs,
 470                                      SUN4I_FRONTEND_CSC_COEF_REG(i),
 471                                      sunxi_bt601_yuv2rgb_coef[i]);
 472         } else {
 473                 bypass = SUN4I_FRONTEND_BYPASS_CSC_EN;
 474         }
 475 
 476         regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
 477                            SUN4I_FRONTEND_BYPASS_CSC_EN, bypass);
 478 
 479         regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
 480                      in_mod_val | in_fmt_val | in_ps_val);
 481 
 482         /*
 483          * TODO: It look like the A31 and A80 at least will need the
 484          * bit 7 (ALPHA_EN) enabled when using a format with alpha (so
 485          * ARGB8888).
 486          */
 487         regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
 488                      out_fmt_val);
 489 
 490         return 0;
 491 }
 492 EXPORT_SYMBOL(sun4i_frontend_update_formats);
 493 
 494 void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
 495                                  struct drm_plane *plane)
 496 {
 497         struct drm_plane_state *state = plane->state;
 498         struct drm_framebuffer *fb = state->fb;
 499         uint32_t luma_width, luma_height;
 500         uint32_t chroma_width, chroma_height;
 501 
 502         /* Set height and width */
 503         DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
 504                          state->crtc_w, state->crtc_h);
 505 
 506         luma_width = state->src_w >> 16;
 507         luma_height = state->src_h >> 16;
 508 
 509         chroma_width = DIV_ROUND_UP(luma_width, fb->format->hsub);
 510         chroma_height = DIV_ROUND_UP(luma_height, fb->format->vsub);
 511 
 512         regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
 513                      SUN4I_FRONTEND_INSIZE(luma_height, luma_width));
 514         regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
 515                      SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width));
 516 
 517         regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
 518                      SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
 519         regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
 520                      SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
 521 
 522         regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
 523                      (luma_width << 16) / state->crtc_w);
 524         regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
 525                      (chroma_width << 16) / state->crtc_w);
 526 
 527         regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
 528                      (luma_height << 16) / state->crtc_h);
 529         regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
 530                      (chroma_height << 16) / state->crtc_h);
 531 
 532         regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
 533                           SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
 534                           SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
 535 }
 536 EXPORT_SYMBOL(sun4i_frontend_update_coord);
 537 
 538 int sun4i_frontend_enable(struct sun4i_frontend *frontend)
 539 {
 540         regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
 541                           SUN4I_FRONTEND_FRM_CTRL_FRM_START,
 542                           SUN4I_FRONTEND_FRM_CTRL_FRM_START);
 543 
 544         return 0;
 545 }
 546 EXPORT_SYMBOL(sun4i_frontend_enable);
 547 
 548 static struct regmap_config sun4i_frontend_regmap_config = {
 549         .reg_bits       = 32,
 550         .val_bits       = 32,
 551         .reg_stride     = 4,
 552         .max_register   = 0x0a14,
 553 };
 554 
 555 static int sun4i_frontend_bind(struct device *dev, struct device *master,
 556                          void *data)
 557 {
 558         struct platform_device *pdev = to_platform_device(dev);
 559         struct sun4i_frontend *frontend;
 560         struct drm_device *drm = data;
 561         struct sun4i_drv *drv = drm->dev_private;
 562         struct resource *res;
 563         void __iomem *regs;
 564 
 565         frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
 566         if (!frontend)
 567                 return -ENOMEM;
 568 
 569         dev_set_drvdata(dev, frontend);
 570         frontend->dev = dev;
 571         frontend->node = dev->of_node;
 572 
 573         frontend->data = of_device_get_match_data(dev);
 574         if (!frontend->data)
 575                 return -ENODEV;
 576 
 577         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 578         regs = devm_ioremap_resource(dev, res);
 579         if (IS_ERR(regs))
 580                 return PTR_ERR(regs);
 581 
 582         frontend->regs = devm_regmap_init_mmio(dev, regs,
 583                                                &sun4i_frontend_regmap_config);
 584         if (IS_ERR(frontend->regs)) {
 585                 dev_err(dev, "Couldn't create the frontend regmap\n");
 586                 return PTR_ERR(frontend->regs);
 587         }
 588 
 589         frontend->reset = devm_reset_control_get(dev, NULL);
 590         if (IS_ERR(frontend->reset)) {
 591                 dev_err(dev, "Couldn't get our reset line\n");
 592                 return PTR_ERR(frontend->reset);
 593         }
 594 
 595         frontend->bus_clk = devm_clk_get(dev, "ahb");
 596         if (IS_ERR(frontend->bus_clk)) {
 597                 dev_err(dev, "Couldn't get our bus clock\n");
 598                 return PTR_ERR(frontend->bus_clk);
 599         }
 600 
 601         frontend->mod_clk = devm_clk_get(dev, "mod");
 602         if (IS_ERR(frontend->mod_clk)) {
 603                 dev_err(dev, "Couldn't get our mod clock\n");
 604                 return PTR_ERR(frontend->mod_clk);
 605         }
 606 
 607         frontend->ram_clk = devm_clk_get(dev, "ram");
 608         if (IS_ERR(frontend->ram_clk)) {
 609                 dev_err(dev, "Couldn't get our ram clock\n");
 610                 return PTR_ERR(frontend->ram_clk);
 611         }
 612 
 613         list_add_tail(&frontend->list, &drv->frontend_list);
 614         pm_runtime_enable(dev);
 615 
 616         return 0;
 617 }
 618 
 619 static void sun4i_frontend_unbind(struct device *dev, struct device *master,
 620                             void *data)
 621 {
 622         struct sun4i_frontend *frontend = dev_get_drvdata(dev);
 623 
 624         list_del(&frontend->list);
 625         pm_runtime_force_suspend(dev);
 626 }
 627 
 628 static const struct component_ops sun4i_frontend_ops = {
 629         .bind   = sun4i_frontend_bind,
 630         .unbind = sun4i_frontend_unbind,
 631 };
 632 
 633 static int sun4i_frontend_probe(struct platform_device *pdev)
 634 {
 635         return component_add(&pdev->dev, &sun4i_frontend_ops);
 636 }
 637 
 638 static int sun4i_frontend_remove(struct platform_device *pdev)
 639 {
 640         component_del(&pdev->dev, &sun4i_frontend_ops);
 641 
 642         return 0;
 643 }
 644 
 645 static int sun4i_frontend_runtime_resume(struct device *dev)
 646 {
 647         struct sun4i_frontend *frontend = dev_get_drvdata(dev);
 648         int ret;
 649 
 650         clk_set_rate(frontend->mod_clk, 300000000);
 651 
 652         clk_prepare_enable(frontend->bus_clk);
 653         clk_prepare_enable(frontend->mod_clk);
 654         clk_prepare_enable(frontend->ram_clk);
 655 
 656         ret = reset_control_reset(frontend->reset);
 657         if (ret) {
 658                 dev_err(dev, "Couldn't reset our device\n");
 659                 return ret;
 660         }
 661 
 662         regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
 663                            SUN4I_FRONTEND_EN_EN,
 664                            SUN4I_FRONTEND_EN_EN);
 665 
 666         sun4i_frontend_scaler_init(frontend);
 667 
 668         return 0;
 669 }
 670 
 671 static int sun4i_frontend_runtime_suspend(struct device *dev)
 672 {
 673         struct sun4i_frontend *frontend = dev_get_drvdata(dev);
 674 
 675         clk_disable_unprepare(frontend->ram_clk);
 676         clk_disable_unprepare(frontend->mod_clk);
 677         clk_disable_unprepare(frontend->bus_clk);
 678 
 679         reset_control_assert(frontend->reset);
 680 
 681         return 0;
 682 }
 683 
 684 static const struct dev_pm_ops sun4i_frontend_pm_ops = {
 685         .runtime_resume         = sun4i_frontend_runtime_resume,
 686         .runtime_suspend        = sun4i_frontend_runtime_suspend,
 687 };
 688 
 689 static const struct sun4i_frontend_data sun4i_a10_frontend = {
 690         .ch_phase               = {
 691                 {
 692                         .horzphase = 0,
 693                         .vertphase = { 0, 0 },
 694                 },
 695                 {
 696                         .horzphase = 0xfc000,
 697                         .vertphase = { 0xfc000, 0xfc000 },
 698                 },
 699         },
 700         .has_coef_rdy           = true,
 701 };
 702 
 703 static const struct sun4i_frontend_data sun8i_a33_frontend = {
 704         .ch_phase               = {
 705                 {
 706                         .horzphase = 0x400,
 707                         .vertphase = { 0x400, 0x400 },
 708                 },
 709                 {
 710                         .horzphase = 0x400,
 711                         .vertphase = { 0x400, 0x400 },
 712                 },
 713         },
 714         .has_coef_access_ctrl   = true,
 715 };
 716 
 717 const struct of_device_id sun4i_frontend_of_table[] = {
 718         {
 719                 .compatible = "allwinner,sun4i-a10-display-frontend",
 720                 .data = &sun4i_a10_frontend
 721         },
 722         {
 723                 .compatible = "allwinner,sun7i-a20-display-frontend",
 724                 .data = &sun4i_a10_frontend
 725         },
 726         {
 727                 .compatible = "allwinner,sun8i-a23-display-frontend",
 728                 .data = &sun8i_a33_frontend
 729         },
 730         {
 731                 .compatible = "allwinner,sun8i-a33-display-frontend",
 732                 .data = &sun8i_a33_frontend
 733         },
 734         { }
 735 };
 736 EXPORT_SYMBOL(sun4i_frontend_of_table);
 737 MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
 738 
 739 static struct platform_driver sun4i_frontend_driver = {
 740         .probe          = sun4i_frontend_probe,
 741         .remove         = sun4i_frontend_remove,
 742         .driver         = {
 743                 .name           = "sun4i-frontend",
 744                 .of_match_table = sun4i_frontend_of_table,
 745                 .pm             = &sun4i_frontend_pm_ops,
 746         },
 747 };
 748 module_platform_driver(sun4i_frontend_driver);
 749 
 750 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 751 MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
 752 MODULE_LICENSE("GPL");

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