root/drivers/media/platform/sti/bdisp/bdisp-hw.c

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

DEFINITIONS

This source file includes following definitions.
  1. bdisp_hw_reset
  2. bdisp_hw_get_and_clear_irq
  3. bdisp_hw_free_nodes
  4. bdisp_hw_alloc_nodes
  5. bdisp_hw_free_filters
  6. bdisp_hw_alloc_filters
  7. bdisp_hw_get_hf_addr
  8. bdisp_hw_get_vf_addr
  9. bdisp_hw_get_inc
  10. bdisp_hw_get_hv_inc
  11. bdisp_hw_get_op_cfg
  12. bdisp_hw_color_format
  13. bdisp_hw_build_node
  14. bdisp_hw_build_all_nodes
  15. bdisp_hw_save_request
  16. bdisp_hw_update

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) STMicroelectronics SA 2014
   4  * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
   5  */
   6 
   7 #include <linux/delay.h>
   8 
   9 #include "bdisp.h"
  10 #include "bdisp-filter.h"
  11 #include "bdisp-reg.h"
  12 
  13 /* Max width of the source frame in a single node */
  14 #define MAX_SRC_WIDTH           2048
  15 
  16 /* Reset & boot poll config */
  17 #define POLL_RST_MAX            500
  18 #define POLL_RST_DELAY_MS       2
  19 
  20 enum bdisp_target_plan {
  21         BDISP_RGB,
  22         BDISP_Y,
  23         BDISP_CBCR
  24 };
  25 
  26 struct bdisp_op_cfg {
  27         bool cconv;          /* RGB - YUV conversion */
  28         bool hflip;          /* Horizontal flip */
  29         bool vflip;          /* Vertical flip */
  30         bool wide;           /* Wide (>MAX_SRC_WIDTH) */
  31         bool scale;          /* Scale */
  32         u16  h_inc;          /* Horizontal increment in 6.10 format */
  33         u16  v_inc;          /* Vertical increment in 6.10 format */
  34         bool src_interlaced; /* is the src an interlaced buffer */
  35         u8   src_nbp;        /* nb of planes of the src */
  36         bool src_yuv;        /* is the src a YUV color format */
  37         bool src_420;        /* is the src 4:2:0 chroma subsampled */
  38         u8   dst_nbp;        /* nb of planes of the dst */
  39         bool dst_yuv;        /* is the dst a YUV color format */
  40         bool dst_420;        /* is the dst 4:2:0 chroma subsampled */
  41 };
  42 
  43 struct bdisp_filter_addr {
  44         u16 min;             /* Filter min scale factor (6.10 fixed point) */
  45         u16 max;             /* Filter max scale factor (6.10 fixed point) */
  46         void *virt;          /* Virtual address for filter table */
  47         dma_addr_t paddr;    /* Physical address for filter table */
  48 };
  49 
  50 static const struct bdisp_filter_h_spec bdisp_h_spec[] = {
  51         {
  52                 .min = 0,
  53                 .max = 921,
  54                 .coef = {
  55                         0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  56                         0x00, 0x00, 0xff, 0x07, 0x3d, 0xfc, 0x01, 0x00,
  57                         0x00, 0x01, 0xfd, 0x11, 0x36, 0xf9, 0x02, 0x00,
  58                         0x00, 0x01, 0xfb, 0x1b, 0x2e, 0xf9, 0x02, 0x00,
  59                         0x00, 0x01, 0xf9, 0x26, 0x26, 0xf9, 0x01, 0x00,
  60                         0x00, 0x02, 0xf9, 0x30, 0x19, 0xfb, 0x01, 0x00,
  61                         0x00, 0x02, 0xf9, 0x39, 0x0e, 0xfd, 0x01, 0x00,
  62                         0x00, 0x01, 0xfc, 0x3e, 0x06, 0xff, 0x00, 0x00
  63                 }
  64         },
  65         {
  66                 .min = 921,
  67                 .max = 1024,
  68                 .coef = {
  69                         0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  70                         0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
  71                         0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
  72                         0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
  73                         0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
  74                         0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
  75                         0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
  76                         0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
  77                 }
  78         },
  79         {
  80                 .min = 1024,
  81                 .max = 1126,
  82                 .coef = {
  83                         0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  84                         0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
  85                         0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
  86                         0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
  87                         0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
  88                         0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
  89                         0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
  90                         0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
  91                 }
  92         },
  93         {
  94                 .min = 1126,
  95                 .max = 1228,
  96                 .coef = {
  97                         0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  98                         0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
  99                         0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
 100                         0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
 101                         0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
 102                         0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
 103                         0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
 104                         0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
 105                 }
 106         },
 107         {
 108                 .min = 1228,
 109                 .max = 1331,
 110                 .coef = {
 111                         0xfd, 0x04, 0xfc, 0x05, 0x39, 0x05, 0xfc, 0x04,
 112                         0xfc, 0x06, 0xf9, 0x0c, 0x39, 0xfe, 0x00, 0x02,
 113                         0xfb, 0x08, 0xf6, 0x17, 0x35, 0xf9, 0x02, 0x00,
 114                         0xfc, 0x08, 0xf4, 0x20, 0x30, 0xf4, 0x05, 0xff,
 115                         0xfd, 0x07, 0xf4, 0x29, 0x28, 0xf3, 0x07, 0xfd,
 116                         0xff, 0x05, 0xf5, 0x31, 0x1f, 0xf3, 0x08, 0xfc,
 117                         0x00, 0x02, 0xf9, 0x38, 0x14, 0xf6, 0x08, 0xfb,
 118                         0x02, 0x00, 0xff, 0x3a, 0x0b, 0xf8, 0x06, 0xfc
 119                 }
 120         },
 121         {
 122                 .min = 1331,
 123                 .max = 1433,
 124                 .coef = {
 125                         0xfc, 0x06, 0xf9, 0x09, 0x34, 0x09, 0xf9, 0x06,
 126                         0xfd, 0x07, 0xf7, 0x10, 0x32, 0x02, 0xfc, 0x05,
 127                         0xfe, 0x07, 0xf6, 0x17, 0x2f, 0xfc, 0xff, 0x04,
 128                         0xff, 0x06, 0xf5, 0x20, 0x2a, 0xf9, 0x01, 0x02,
 129                         0x00, 0x04, 0xf6, 0x27, 0x25, 0xf6, 0x04, 0x00,
 130                         0x02, 0x01, 0xf9, 0x2d, 0x1d, 0xf5, 0x06, 0xff,
 131                         0x04, 0xff, 0xfd, 0x31, 0x15, 0xf5, 0x07, 0xfe,
 132                         0x05, 0xfc, 0x02, 0x35, 0x0d, 0xf7, 0x07, 0xfd
 133                 }
 134         },
 135         {
 136                 .min = 1433,
 137                 .max = 1536,
 138                 .coef = {
 139                         0xfe, 0x06, 0xf8, 0x0b, 0x30, 0x0b, 0xf8, 0x06,
 140                         0xff, 0x06, 0xf7, 0x12, 0x2d, 0x05, 0xfa, 0x06,
 141                         0x00, 0x04, 0xf6, 0x18, 0x2c, 0x00, 0xfc, 0x06,
 142                         0x01, 0x02, 0xf7, 0x1f, 0x27, 0xfd, 0xff, 0x04,
 143                         0x03, 0x00, 0xf9, 0x24, 0x24, 0xf9, 0x00, 0x03,
 144                         0x04, 0xff, 0xfd, 0x29, 0x1d, 0xf7, 0x02, 0x01,
 145                         0x06, 0xfc, 0x00, 0x2d, 0x17, 0xf6, 0x04, 0x00,
 146                         0x06, 0xfa, 0x05, 0x30, 0x0f, 0xf7, 0x06, 0xff
 147                 }
 148         },
 149         {
 150                 .min = 1536,
 151                 .max = 2048,
 152                 .coef = {
 153                         0x05, 0xfd, 0xfb, 0x13, 0x25, 0x13, 0xfb, 0xfd,
 154                         0x05, 0xfc, 0xfd, 0x17, 0x24, 0x0f, 0xf9, 0xff,
 155                         0x04, 0xfa, 0xff, 0x1b, 0x24, 0x0b, 0xf9, 0x00,
 156                         0x03, 0xf9, 0x01, 0x1f, 0x23, 0x08, 0xf8, 0x01,
 157                         0x02, 0xf9, 0x04, 0x22, 0x20, 0x04, 0xf9, 0x02,
 158                         0x01, 0xf8, 0x08, 0x25, 0x1d, 0x01, 0xf9, 0x03,
 159                         0x00, 0xf9, 0x0c, 0x25, 0x1a, 0xfe, 0xfa, 0x04,
 160                         0xff, 0xf9, 0x10, 0x26, 0x15, 0xfc, 0xfc, 0x05
 161                 }
 162         },
 163         {
 164                 .min = 2048,
 165                 .max = 3072,
 166                 .coef = {
 167                         0xfc, 0xfd, 0x06, 0x13, 0x18, 0x13, 0x06, 0xfd,
 168                         0xfc, 0xfe, 0x08, 0x15, 0x17, 0x12, 0x04, 0xfc,
 169                         0xfb, 0xfe, 0x0a, 0x16, 0x18, 0x10, 0x03, 0xfc,
 170                         0xfb, 0x00, 0x0b, 0x18, 0x17, 0x0f, 0x01, 0xfb,
 171                         0xfb, 0x00, 0x0d, 0x19, 0x17, 0x0d, 0x00, 0xfb,
 172                         0xfb, 0x01, 0x0f, 0x19, 0x16, 0x0b, 0x00, 0xfb,
 173                         0xfc, 0x03, 0x11, 0x19, 0x15, 0x09, 0xfe, 0xfb,
 174                         0xfc, 0x04, 0x12, 0x1a, 0x12, 0x08, 0xfe, 0xfc
 175                 }
 176         },
 177         {
 178                 .min = 3072,
 179                 .max = 4096,
 180                 .coef = {
 181                         0xfe, 0x02, 0x09, 0x0f, 0x0e, 0x0f, 0x09, 0x02,
 182                         0xff, 0x02, 0x09, 0x0f, 0x10, 0x0e, 0x08, 0x01,
 183                         0xff, 0x03, 0x0a, 0x10, 0x10, 0x0d, 0x07, 0x00,
 184                         0x00, 0x04, 0x0b, 0x10, 0x0f, 0x0c, 0x06, 0x00,
 185                         0x00, 0x05, 0x0c, 0x10, 0x0e, 0x0c, 0x05, 0x00,
 186                         0x00, 0x06, 0x0c, 0x11, 0x0e, 0x0b, 0x04, 0x00,
 187                         0x00, 0x07, 0x0d, 0x11, 0x0f, 0x0a, 0x03, 0xff,
 188                         0x01, 0x08, 0x0e, 0x11, 0x0e, 0x09, 0x02, 0xff
 189                 }
 190         },
 191         {
 192                 .min = 4096,
 193                 .max = 5120,
 194                 .coef = {
 195                         0x00, 0x04, 0x09, 0x0c, 0x0e, 0x0c, 0x09, 0x04,
 196                         0x01, 0x05, 0x09, 0x0c, 0x0d, 0x0c, 0x08, 0x04,
 197                         0x01, 0x05, 0x0a, 0x0c, 0x0e, 0x0b, 0x08, 0x03,
 198                         0x02, 0x06, 0x0a, 0x0d, 0x0c, 0x0b, 0x07, 0x03,
 199                         0x02, 0x07, 0x0a, 0x0d, 0x0d, 0x0a, 0x07, 0x02,
 200                         0x03, 0x07, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x02,
 201                         0x03, 0x08, 0x0b, 0x0d, 0x0d, 0x0a, 0x05, 0x01,
 202                         0x04, 0x08, 0x0c, 0x0d, 0x0c, 0x09, 0x05, 0x01
 203                 }
 204         },
 205         {
 206                 .min = 5120,
 207                 .max = 65535,
 208                 .coef = {
 209                         0x03, 0x06, 0x09, 0x0b, 0x09, 0x0b, 0x09, 0x06,
 210                         0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
 211                         0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
 212                         0x04, 0x07, 0x09, 0x0b, 0x0b, 0x0a, 0x08, 0x04,
 213                         0x04, 0x07, 0x0a, 0x0b, 0x0b, 0x0a, 0x07, 0x04,
 214                         0x04, 0x08, 0x0a, 0x0b, 0x0b, 0x09, 0x07, 0x04,
 215                         0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03,
 216                         0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03
 217                 }
 218         }
 219 };
 220 
 221 #define NB_H_FILTER ARRAY_SIZE(bdisp_h_spec)
 222 
 223 
 224 static const struct bdisp_filter_v_spec bdisp_v_spec[] = {
 225         {
 226                 .min = 0,
 227                 .max = 1024,
 228                 .coef = {
 229                         0x00, 0x00, 0x40, 0x00, 0x00,
 230                         0x00, 0x06, 0x3d, 0xfd, 0x00,
 231                         0xfe, 0x0f, 0x38, 0xfb, 0x00,
 232                         0xfd, 0x19, 0x2f, 0xfb, 0x00,
 233                         0xfc, 0x24, 0x24, 0xfc, 0x00,
 234                         0xfb, 0x2f, 0x19, 0xfd, 0x00,
 235                         0xfb, 0x38, 0x0f, 0xfe, 0x00,
 236                         0xfd, 0x3d, 0x06, 0x00, 0x00
 237                 }
 238         },
 239         {
 240                 .min = 1024,
 241                 .max = 1331,
 242                 .coef = {
 243                         0xfc, 0x05, 0x3e, 0x05, 0xfc,
 244                         0xf8, 0x0e, 0x3b, 0xff, 0x00,
 245                         0xf5, 0x18, 0x38, 0xf9, 0x02,
 246                         0xf4, 0x21, 0x31, 0xf5, 0x05,
 247                         0xf4, 0x2a, 0x27, 0xf4, 0x07,
 248                         0xf6, 0x30, 0x1e, 0xf4, 0x08,
 249                         0xf9, 0x35, 0x15, 0xf6, 0x07,
 250                         0xff, 0x37, 0x0b, 0xf9, 0x06
 251                 }
 252         },
 253         {
 254                 .min = 1331,
 255                 .max = 1433,
 256                 .coef = {
 257                         0xf8, 0x0a, 0x3c, 0x0a, 0xf8,
 258                         0xf6, 0x12, 0x3b, 0x02, 0xfb,
 259                         0xf4, 0x1b, 0x35, 0xfd, 0xff,
 260                         0xf4, 0x23, 0x30, 0xf8, 0x01,
 261                         0xf6, 0x29, 0x27, 0xf6, 0x04,
 262                         0xf9, 0x2e, 0x1e, 0xf5, 0x06,
 263                         0xfd, 0x31, 0x16, 0xf6, 0x06,
 264                         0x02, 0x32, 0x0d, 0xf8, 0x07
 265                 }
 266         },
 267         {
 268                 .min = 1433,
 269                 .max = 1536,
 270                 .coef = {
 271                         0xf6, 0x0e, 0x38, 0x0e, 0xf6,
 272                         0xf5, 0x15, 0x38, 0x06, 0xf8,
 273                         0xf5, 0x1d, 0x33, 0x00, 0xfb,
 274                         0xf6, 0x23, 0x2d, 0xfc, 0xfe,
 275                         0xf9, 0x28, 0x26, 0xf9, 0x00,
 276                         0xfc, 0x2c, 0x1e, 0xf7, 0x03,
 277                         0x00, 0x2e, 0x18, 0xf6, 0x04,
 278                         0x05, 0x2e, 0x11, 0xf7, 0x05
 279                 }
 280         },
 281         {
 282                 .min = 1536,
 283                 .max = 2048,
 284                 .coef = {
 285                         0xfb, 0x13, 0x24, 0x13, 0xfb,
 286                         0xfd, 0x17, 0x23, 0x0f, 0xfa,
 287                         0xff, 0x1a, 0x23, 0x0b, 0xf9,
 288                         0x01, 0x1d, 0x22, 0x07, 0xf9,
 289                         0x04, 0x20, 0x1f, 0x04, 0xf9,
 290                         0x07, 0x22, 0x1c, 0x01, 0xfa,
 291                         0x0b, 0x24, 0x17, 0xff, 0xfb,
 292                         0x0f, 0x24, 0x14, 0xfd, 0xfc
 293                 }
 294         },
 295         {
 296                 .min = 2048,
 297                 .max = 3072,
 298                 .coef = {
 299                         0x05, 0x10, 0x16, 0x10, 0x05,
 300                         0x06, 0x11, 0x16, 0x0f, 0x04,
 301                         0x08, 0x13, 0x15, 0x0e, 0x02,
 302                         0x09, 0x14, 0x16, 0x0c, 0x01,
 303                         0x0b, 0x15, 0x15, 0x0b, 0x00,
 304                         0x0d, 0x16, 0x13, 0x0a, 0x00,
 305                         0x0f, 0x17, 0x13, 0x08, 0xff,
 306                         0x11, 0x18, 0x12, 0x07, 0xfe
 307                 }
 308         },
 309         {
 310                 .min = 3072,
 311                 .max = 4096,
 312                 .coef = {
 313                         0x09, 0x0f, 0x10, 0x0f, 0x09,
 314                         0x09, 0x0f, 0x12, 0x0e, 0x08,
 315                         0x0a, 0x10, 0x11, 0x0e, 0x07,
 316                         0x0b, 0x11, 0x11, 0x0d, 0x06,
 317                         0x0c, 0x11, 0x12, 0x0c, 0x05,
 318                         0x0d, 0x12, 0x11, 0x0c, 0x04,
 319                         0x0e, 0x12, 0x11, 0x0b, 0x04,
 320                         0x0f, 0x13, 0x11, 0x0a, 0x03
 321                 }
 322         },
 323         {
 324                 .min = 4096,
 325                 .max = 5120,
 326                 .coef = {
 327                         0x0a, 0x0e, 0x10, 0x0e, 0x0a,
 328                         0x0b, 0x0e, 0x0f, 0x0e, 0x0a,
 329                         0x0b, 0x0f, 0x10, 0x0d, 0x09,
 330                         0x0c, 0x0f, 0x10, 0x0d, 0x08,
 331                         0x0d, 0x0f, 0x0f, 0x0d, 0x08,
 332                         0x0d, 0x10, 0x10, 0x0c, 0x07,
 333                         0x0e, 0x10, 0x0f, 0x0c, 0x07,
 334                         0x0f, 0x10, 0x10, 0x0b, 0x06
 335                 }
 336         },
 337         {
 338                 .min = 5120,
 339                 .max = 65535,
 340                 .coef = {
 341                         0x0b, 0x0e, 0x0e, 0x0e, 0x0b,
 342                         0x0b, 0x0e, 0x0f, 0x0d, 0x0b,
 343                         0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
 344                         0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
 345                         0x0d, 0x0f, 0x0e, 0x0d, 0x09,
 346                         0x0d, 0x0f, 0x0f, 0x0c, 0x09,
 347                         0x0e, 0x0f, 0x0e, 0x0c, 0x09,
 348                         0x0e, 0x0f, 0x0f, 0x0c, 0x08
 349                 }
 350         }
 351 };
 352 
 353 #define NB_V_FILTER ARRAY_SIZE(bdisp_v_spec)
 354 
 355 static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];
 356 static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER];
 357 
 358 /**
 359  * bdisp_hw_reset
 360  * @bdisp:      bdisp entity
 361  *
 362  * Resets HW
 363  *
 364  * RETURNS:
 365  * 0 on success.
 366  */
 367 int bdisp_hw_reset(struct bdisp_dev *bdisp)
 368 {
 369         unsigned int i;
 370 
 371         dev_dbg(bdisp->dev, "%s\n", __func__);
 372 
 373         /* Mask Interrupt */
 374         writel(0, bdisp->regs + BLT_ITM0);
 375 
 376         /* Reset */
 377         writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET,
 378                bdisp->regs + BLT_CTL);
 379         writel(0, bdisp->regs + BLT_CTL);
 380 
 381         /* Wait for reset done */
 382         for (i = 0; i < POLL_RST_MAX; i++) {
 383                 if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
 384                         break;
 385                 udelay(POLL_RST_DELAY_MS * 1000);
 386         }
 387         if (i == POLL_RST_MAX)
 388                 dev_err(bdisp->dev, "Reset timeout\n");
 389 
 390         return (i == POLL_RST_MAX) ? -EAGAIN : 0;
 391 }
 392 
 393 /**
 394  * bdisp_hw_get_and_clear_irq
 395  * @bdisp:      bdisp entity
 396  *
 397  * Read then reset interrupt status
 398  *
 399  * RETURNS:
 400  * 0 if expected interrupt was raised.
 401  */
 402 int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp)
 403 {
 404         u32 its;
 405 
 406         its = readl(bdisp->regs + BLT_ITS);
 407 
 408         /* Check for the only expected IT: LastNode of AQ1 */
 409         if (!(its & BLT_ITS_AQ1_LNA)) {
 410                 dev_dbg(bdisp->dev, "Unexpected IT status: 0x%08X\n", its);
 411                 writel(its, bdisp->regs + BLT_ITS);
 412                 return -1;
 413         }
 414 
 415         /* Clear and mask */
 416         writel(its, bdisp->regs + BLT_ITS);
 417         writel(0, bdisp->regs + BLT_ITM0);
 418 
 419         return 0;
 420 }
 421 
 422 /**
 423  * bdisp_hw_free_nodes
 424  * @ctx:        bdisp context
 425  *
 426  * Free node memory
 427  *
 428  * RETURNS:
 429  * None
 430  */
 431 void bdisp_hw_free_nodes(struct bdisp_ctx *ctx)
 432 {
 433         if (ctx && ctx->node[0])
 434                 dma_free_attrs(ctx->bdisp_dev->dev,
 435                                sizeof(struct bdisp_node) * MAX_NB_NODE,
 436                                ctx->node[0], ctx->node_paddr[0],
 437                                DMA_ATTR_WRITE_COMBINE);
 438 }
 439 
 440 /**
 441  * bdisp_hw_alloc_nodes
 442  * @ctx:        bdisp context
 443  *
 444  * Allocate dma memory for nodes
 445  *
 446  * RETURNS:
 447  * 0 on success
 448  */
 449 int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx)
 450 {
 451         struct device *dev = ctx->bdisp_dev->dev;
 452         unsigned int i, node_size = sizeof(struct bdisp_node);
 453         void *base;
 454         dma_addr_t paddr;
 455 
 456         /* Allocate all the nodes within a single memory page */
 457         base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr,
 458                                GFP_KERNEL, DMA_ATTR_WRITE_COMBINE);
 459         if (!base) {
 460                 dev_err(dev, "%s no mem\n", __func__);
 461                 return -ENOMEM;
 462         }
 463 
 464         memset(base, 0, node_size * MAX_NB_NODE);
 465 
 466         for (i = 0; i < MAX_NB_NODE; i++) {
 467                 ctx->node[i] = base;
 468                 ctx->node_paddr[i] = paddr;
 469                 dev_dbg(dev, "node[%d]=0x%p (paddr=%pad)\n", i, ctx->node[i],
 470                         &paddr);
 471                 base += node_size;
 472                 paddr += node_size;
 473         }
 474 
 475         return 0;
 476 }
 477 
 478 /**
 479  * bdisp_hw_free_filters
 480  * @dev:        device
 481  *
 482  * Free filters memory
 483  *
 484  * RETURNS:
 485  * None
 486  */
 487 void bdisp_hw_free_filters(struct device *dev)
 488 {
 489         int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
 490 
 491         if (bdisp_h_filter[0].virt)
 492                 dma_free_attrs(dev, size, bdisp_h_filter[0].virt,
 493                                bdisp_h_filter[0].paddr, DMA_ATTR_WRITE_COMBINE);
 494 }
 495 
 496 /**
 497  * bdisp_hw_alloc_filters
 498  * @dev:        device
 499  *
 500  * Allocate dma memory for filters
 501  *
 502  * RETURNS:
 503  * 0 on success
 504  */
 505 int bdisp_hw_alloc_filters(struct device *dev)
 506 {
 507         unsigned int i, size;
 508         void *base;
 509         dma_addr_t paddr;
 510 
 511         /* Allocate all the filters within a single memory page */
 512         size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
 513         base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL,
 514                                DMA_ATTR_WRITE_COMBINE);
 515         if (!base)
 516                 return -ENOMEM;
 517 
 518         /* Setup filter addresses */
 519         for (i = 0; i < NB_H_FILTER; i++) {
 520                 bdisp_h_filter[i].min = bdisp_h_spec[i].min;
 521                 bdisp_h_filter[i].max = bdisp_h_spec[i].max;
 522                 memcpy(base, bdisp_h_spec[i].coef, BDISP_HF_NB);
 523                 bdisp_h_filter[i].virt = base;
 524                 bdisp_h_filter[i].paddr = paddr;
 525                 base += BDISP_HF_NB;
 526                 paddr += BDISP_HF_NB;
 527         }
 528 
 529         for (i = 0; i < NB_V_FILTER; i++) {
 530                 bdisp_v_filter[i].min = bdisp_v_spec[i].min;
 531                 bdisp_v_filter[i].max = bdisp_v_spec[i].max;
 532                 memcpy(base, bdisp_v_spec[i].coef, BDISP_VF_NB);
 533                 bdisp_v_filter[i].virt = base;
 534                 bdisp_v_filter[i].paddr = paddr;
 535                 base += BDISP_VF_NB;
 536                 paddr += BDISP_VF_NB;
 537         }
 538 
 539         return 0;
 540 }
 541 
 542 /**
 543  * bdisp_hw_get_hf_addr
 544  * @inc:        resize increment
 545  *
 546  * Find the horizontal filter table that fits the resize increment
 547  *
 548  * RETURNS:
 549  * table physical address
 550  */
 551 static dma_addr_t bdisp_hw_get_hf_addr(u16 inc)
 552 {
 553         unsigned int i;
 554 
 555         for (i = NB_H_FILTER - 1; i > 0; i--)
 556                 if ((bdisp_h_filter[i].min < inc) &&
 557                     (inc <= bdisp_h_filter[i].max))
 558                         break;
 559 
 560         return bdisp_h_filter[i].paddr;
 561 }
 562 
 563 /**
 564  * bdisp_hw_get_vf_addr
 565  * @inc:        resize increment
 566  *
 567  * Find the vertical filter table that fits the resize increment
 568  *
 569  * RETURNS:
 570  * table physical address
 571  */
 572 static dma_addr_t bdisp_hw_get_vf_addr(u16 inc)
 573 {
 574         unsigned int i;
 575 
 576         for (i = NB_V_FILTER - 1; i > 0; i--)
 577                 if ((bdisp_v_filter[i].min < inc) &&
 578                     (inc <= bdisp_v_filter[i].max))
 579                         break;
 580 
 581         return bdisp_v_filter[i].paddr;
 582 }
 583 
 584 /**
 585  * bdisp_hw_get_inc
 586  * @from:       input size
 587  * @to:         output size
 588  * @inc:        resize increment in 6.10 format
 589  *
 590  * Computes the increment (inverse of scale) in 6.10 format
 591  *
 592  * RETURNS:
 593  * 0 on success
 594  */
 595 static int bdisp_hw_get_inc(u32 from, u32 to, u16 *inc)
 596 {
 597         u32 tmp;
 598 
 599         if (!to)
 600                 return -EINVAL;
 601 
 602         if (to == from) {
 603                 *inc = 1 << 10;
 604                 return 0;
 605         }
 606 
 607         tmp = (from << 10) / to;
 608         if ((tmp > 0xFFFF) || (!tmp))
 609                 /* overflow (downscale x 63) or too small (upscale x 1024) */
 610                 return -EINVAL;
 611 
 612         *inc = (u16)tmp;
 613 
 614         return 0;
 615 }
 616 
 617 /**
 618  * bdisp_hw_get_hv_inc
 619  * @ctx:        device context
 620  * @h_inc:      horizontal increment
 621  * @v_inc:      vertical increment
 622  *
 623  * Computes the horizontal & vertical increments (inverse of scale)
 624  *
 625  * RETURNS:
 626  * 0 on success
 627  */
 628 static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc)
 629 {
 630         u32 src_w, src_h, dst_w, dst_h;
 631 
 632         src_w = ctx->src.crop.width;
 633         src_h = ctx->src.crop.height;
 634         dst_w = ctx->dst.crop.width;
 635         dst_h = ctx->dst.crop.height;
 636 
 637         if (bdisp_hw_get_inc(src_w, dst_w, h_inc) ||
 638             bdisp_hw_get_inc(src_h, dst_h, v_inc)) {
 639                 dev_err(ctx->bdisp_dev->dev,
 640                         "scale factors failed (%dx%d)->(%dx%d)\n",
 641                         src_w, src_h, dst_w, dst_h);
 642                 return -EINVAL;
 643         }
 644 
 645         return 0;
 646 }
 647 
 648 /**
 649  * bdisp_hw_get_op_cfg
 650  * @ctx:        device context
 651  * @c:          operation configuration
 652  *
 653  * Check which blitter operations are expected and sets the scaling increments
 654  *
 655  * RETURNS:
 656  * 0 on success
 657  */
 658 static int bdisp_hw_get_op_cfg(struct bdisp_ctx *ctx, struct bdisp_op_cfg *c)
 659 {
 660         struct device *dev = ctx->bdisp_dev->dev;
 661         struct bdisp_frame *src = &ctx->src;
 662         struct bdisp_frame *dst = &ctx->dst;
 663 
 664         if (src->width > MAX_SRC_WIDTH * MAX_VERTICAL_STRIDES) {
 665                 dev_err(dev, "Image width out of HW caps\n");
 666                 return -EINVAL;
 667         }
 668 
 669         c->wide = src->width > MAX_SRC_WIDTH;
 670 
 671         c->hflip = ctx->hflip;
 672         c->vflip = ctx->vflip;
 673 
 674         c->src_interlaced = (src->field == V4L2_FIELD_INTERLACED);
 675 
 676         c->src_nbp = src->fmt->nb_planes;
 677         c->src_yuv = (src->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
 678                         (src->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
 679         c->src_420 = c->src_yuv;
 680 
 681         c->dst_nbp = dst->fmt->nb_planes;
 682         c->dst_yuv = (dst->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
 683                         (dst->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
 684         c->dst_420 = c->dst_yuv;
 685 
 686         c->cconv = (c->src_yuv != c->dst_yuv);
 687 
 688         if (bdisp_hw_get_hv_inc(ctx, &c->h_inc, &c->v_inc)) {
 689                 dev_err(dev, "Scale factor out of HW caps\n");
 690                 return -EINVAL;
 691         }
 692 
 693         /* Deinterlacing adjustment : stretch a field to a frame */
 694         if (c->src_interlaced)
 695                 c->v_inc /= 2;
 696 
 697         if ((c->h_inc != (1 << 10)) || (c->v_inc != (1 << 10)))
 698                 c->scale = true;
 699         else
 700                 c->scale = false;
 701 
 702         return 0;
 703 }
 704 
 705 /**
 706  * bdisp_hw_color_format
 707  * @pixelformat: v4l2 pixel format
 708  *
 709  * v4l2 to bdisp pixel format convert
 710  *
 711  * RETURNS:
 712  * bdisp pixel format
 713  */
 714 static u32 bdisp_hw_color_format(u32 pixelformat)
 715 {
 716         u32 ret;
 717 
 718         switch (pixelformat) {
 719         case V4L2_PIX_FMT_YUV420:
 720                 ret = (BDISP_YUV_3B << BLT_TTY_COL_SHIFT);
 721                 break;
 722         case V4L2_PIX_FMT_NV12:
 723                 ret = (BDISP_NV12 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
 724                 break;
 725         case V4L2_PIX_FMT_RGB565:
 726                 ret = (BDISP_RGB565 << BLT_TTY_COL_SHIFT);
 727                 break;
 728         case V4L2_PIX_FMT_XBGR32: /* This V4L format actually refers to xRGB */
 729                 ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT);
 730                 break;
 731         case V4L2_PIX_FMT_RGB24:  /* RGB888 format */
 732                 ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
 733                 break;
 734         case V4L2_PIX_FMT_ABGR32: /* This V4L format actually refers to ARGB */
 735 
 736         default:
 737                 ret = (BDISP_ARGB8888 << BLT_TTY_COL_SHIFT) | BLT_TTY_ALPHA_R;
 738                 break;
 739         }
 740 
 741         return ret;
 742 }
 743 
 744 /**
 745  * bdisp_hw_build_node
 746  * @ctx:        device context
 747  * @cfg:        operation configuration
 748  * @node:       node to be set
 749  * @t_plan:     whether the node refers to a RGB/Y or a CbCr plane
 750  * @src_x_offset: x offset in the source image
 751  *
 752  * Build a node
 753  *
 754  * RETURNS:
 755  * None
 756  */
 757 static void bdisp_hw_build_node(struct bdisp_ctx *ctx,
 758                                 struct bdisp_op_cfg *cfg,
 759                                 struct bdisp_node *node,
 760                                 enum bdisp_target_plan t_plan, int src_x_offset)
 761 {
 762         struct bdisp_frame *src = &ctx->src;
 763         struct bdisp_frame *dst = &ctx->dst;
 764         u16 h_inc, v_inc, yh_inc, yv_inc;
 765         struct v4l2_rect src_rect = src->crop;
 766         struct v4l2_rect dst_rect = dst->crop;
 767         int dst_x_offset;
 768         s32 dst_width = dst->crop.width;
 769         u32 src_fmt, dst_fmt;
 770         const u32 *ivmx;
 771 
 772         dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__);
 773 
 774         memset(node, 0, sizeof(*node));
 775 
 776         /* Adjust src and dst areas wrt src_x_offset */
 777         src_rect.left += src_x_offset;
 778         src_rect.width -= src_x_offset;
 779         src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width);
 780 
 781         dst_x_offset = (src_x_offset * dst_width) / ctx->src.crop.width;
 782         dst_rect.left += dst_x_offset;
 783         dst_rect.width = (src_rect.width * dst_width) / ctx->src.crop.width;
 784 
 785         /* General */
 786         src_fmt = src->fmt->pixelformat;
 787         dst_fmt = dst->fmt->pixelformat;
 788 
 789         node->nip = 0;
 790         node->cic = BLT_CIC_ALL_GRP;
 791         node->ack = BLT_ACK_BYPASS_S2S3;
 792 
 793         switch (cfg->src_nbp) {
 794         case 1:
 795                 /* Src2 = RGB / Src1 = Src3 = off */
 796                 node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF;
 797                 break;
 798         case 2:
 799                 /* Src3 = Y
 800                  * Src2 = CbCr or ColorFill if writing the Y plane
 801                  * Src1 = off */
 802                 node->ins = BLT_INS_S1_OFF | BLT_INS_S3_MEM;
 803                 if (t_plan == BDISP_Y)
 804                         node->ins |= BLT_INS_S2_CF;
 805                 else
 806                         node->ins |= BLT_INS_S2_MEM;
 807                 break;
 808         case 3:
 809         default:
 810                 /* Src3 = Y
 811                  * Src2 = Cb or ColorFill if writing the Y plane
 812                  * Src1 = Cr or ColorFill if writing the Y plane */
 813                 node->ins = BLT_INS_S3_MEM;
 814                 if (t_plan == BDISP_Y)
 815                         node->ins |= BLT_INS_S2_CF | BLT_INS_S1_CF;
 816                 else
 817                         node->ins |= BLT_INS_S2_MEM | BLT_INS_S1_MEM;
 818                 break;
 819         }
 820 
 821         /* Color convert */
 822         node->ins |= cfg->cconv ? BLT_INS_IVMX : 0;
 823         /* Scale needed if scaling OR 4:2:0 up/downsampling */
 824         node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ?
 825                         BLT_INS_SCALE : 0;
 826 
 827         /* Target */
 828         node->tba = (t_plan == BDISP_CBCR) ? dst->paddr[1] : dst->paddr[0];
 829 
 830         node->tty = dst->bytesperline;
 831         node->tty |= bdisp_hw_color_format(dst_fmt);
 832         node->tty |= BLT_TTY_DITHER;
 833         node->tty |= (t_plan == BDISP_CBCR) ? BLT_TTY_CHROMA : 0;
 834         node->tty |= cfg->hflip ? BLT_TTY_HSO : 0;
 835         node->tty |= cfg->vflip ? BLT_TTY_VSO : 0;
 836 
 837         if (cfg->dst_420 && (t_plan == BDISP_CBCR)) {
 838                 /* 420 chroma downsampling */
 839                 dst_rect.height /= 2;
 840                 dst_rect.width /= 2;
 841                 dst_rect.left /= 2;
 842                 dst_rect.top /= 2;
 843                 dst_x_offset /= 2;
 844                 dst_width /= 2;
 845         }
 846 
 847         node->txy = cfg->vflip ? (dst_rect.height - 1) : dst_rect.top;
 848         node->txy <<= 16;
 849         node->txy |= cfg->hflip ? (dst_width - dst_x_offset - 1) :
 850                         dst_rect.left;
 851 
 852         node->tsz = dst_rect.height << 16 | dst_rect.width;
 853 
 854         if (cfg->src_interlaced) {
 855                 /* handle only the top field which is half height of a frame */
 856                 src_rect.top /= 2;
 857                 src_rect.height /= 2;
 858         }
 859 
 860         if (cfg->src_nbp == 1) {
 861                 /* Src 2 : RGB */
 862                 node->s2ba = src->paddr[0];
 863 
 864                 node->s2ty = src->bytesperline;
 865                 if (cfg->src_interlaced)
 866                         node->s2ty *= 2;
 867 
 868                 node->s2ty |= bdisp_hw_color_format(src_fmt);
 869 
 870                 node->s2xy = src_rect.top << 16 | src_rect.left;
 871                 node->s2sz = src_rect.height << 16 | src_rect.width;
 872         } else {
 873                 /* Src 2 : Cb or CbCr */
 874                 if (cfg->src_420) {
 875                         /* 420 chroma upsampling */
 876                         src_rect.top /= 2;
 877                         src_rect.left /= 2;
 878                         src_rect.width /= 2;
 879                         src_rect.height /= 2;
 880                 }
 881 
 882                 node->s2ba = src->paddr[1];
 883 
 884                 node->s2ty = src->bytesperline;
 885                 if (cfg->src_nbp == 3)
 886                         node->s2ty /= 2;
 887                 if (cfg->src_interlaced)
 888                         node->s2ty *= 2;
 889 
 890                 node->s2ty |= bdisp_hw_color_format(src_fmt);
 891 
 892                 node->s2xy = src_rect.top << 16 | src_rect.left;
 893                 node->s2sz = src_rect.height << 16 | src_rect.width;
 894 
 895                 if (cfg->src_nbp == 3) {
 896                         /* Src 1 : Cr */
 897                         node->s1ba = src->paddr[2];
 898 
 899                         node->s1ty = node->s2ty;
 900                         node->s1xy = node->s2xy;
 901                 }
 902 
 903                 /* Src 3 : Y */
 904                 node->s3ba = src->paddr[0];
 905 
 906                 node->s3ty = src->bytesperline;
 907                 if (cfg->src_interlaced)
 908                         node->s3ty *= 2;
 909                 node->s3ty |= bdisp_hw_color_format(src_fmt);
 910 
 911                 if ((t_plan != BDISP_CBCR) && cfg->src_420) {
 912                         /* No chroma upsampling for output RGB / Y plane */
 913                         node->s3xy = node->s2xy * 2;
 914                         node->s3sz = node->s2sz * 2;
 915                 } else {
 916                         /* No need to read Y (Src3) when writing Chroma */
 917                         node->s3ty |= BLT_S3TY_BLANK_ACC;
 918                         node->s3xy = node->s2xy;
 919                         node->s3sz = node->s2sz;
 920                 }
 921         }
 922 
 923         /* Resize (scale OR 4:2:0: chroma up/downsampling) */
 924         if (node->ins & BLT_INS_SCALE) {
 925                 /* no need to compute Y when writing CbCr from RGB input */
 926                 bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv;
 927 
 928                 /* FCTL */
 929                 if (cfg->scale) {
 930                         node->fctl = BLT_FCTL_HV_SCALE;
 931                         if (!skip_y)
 932                                 node->fctl |= BLT_FCTL_Y_HV_SCALE;
 933                 } else {
 934                         node->fctl = BLT_FCTL_HV_SAMPLE;
 935                         if (!skip_y)
 936                                 node->fctl |= BLT_FCTL_Y_HV_SAMPLE;
 937                 }
 938 
 939                 /* RSF - Chroma may need to be up/downsampled */
 940                 h_inc = cfg->h_inc;
 941                 v_inc = cfg->v_inc;
 942                 if (!cfg->src_420 && cfg->dst_420 && (t_plan == BDISP_CBCR)) {
 943                         /* RGB to 4:2:0 for Chroma: downsample */
 944                         h_inc *= 2;
 945                         v_inc *= 2;
 946                 } else if (cfg->src_420 && !cfg->dst_420) {
 947                         /* 4:2:0: to RGB: upsample*/
 948                         h_inc /= 2;
 949                         v_inc /= 2;
 950                 }
 951                 node->rsf = v_inc << 16 | h_inc;
 952 
 953                 /* RZI */
 954                 node->rzi = BLT_RZI_DEFAULT;
 955 
 956                 /* Filter table physical addr */
 957                 node->hfp = bdisp_hw_get_hf_addr(h_inc);
 958                 node->vfp = bdisp_hw_get_vf_addr(v_inc);
 959 
 960                 /* Y version */
 961                 if (!skip_y) {
 962                         yh_inc = cfg->h_inc;
 963                         yv_inc = cfg->v_inc;
 964 
 965                         node->y_rsf = yv_inc << 16 | yh_inc;
 966                         node->y_rzi = BLT_RZI_DEFAULT;
 967                         node->y_hfp = bdisp_hw_get_hf_addr(yh_inc);
 968                         node->y_vfp = bdisp_hw_get_vf_addr(yv_inc);
 969                 }
 970         }
 971 
 972         /* Versatile matrix for RGB / YUV conversion */
 973         if (cfg->cconv) {
 974                 ivmx = cfg->src_yuv ? bdisp_yuv_to_rgb : bdisp_rgb_to_yuv;
 975 
 976                 node->ivmx0 = ivmx[0];
 977                 node->ivmx1 = ivmx[1];
 978                 node->ivmx2 = ivmx[2];
 979                 node->ivmx3 = ivmx[3];
 980         }
 981 }
 982 
 983 /**
 984  * bdisp_hw_build_all_nodes
 985  * @ctx:        device context
 986  *
 987  * Build all the nodes for the blitter operation
 988  *
 989  * RETURNS:
 990  * 0 on success
 991  */
 992 static int bdisp_hw_build_all_nodes(struct bdisp_ctx *ctx)
 993 {
 994         struct bdisp_op_cfg cfg;
 995         unsigned int i, nid = 0;
 996         int src_x_offset = 0;
 997 
 998         for (i = 0; i < MAX_NB_NODE; i++)
 999                 if (!ctx->node[i]) {
1000                         dev_err(ctx->bdisp_dev->dev, "node %d is null\n", i);
1001                         return -EINVAL;
1002                 }
1003 
1004         /* Get configuration (scale, flip, ...) */
1005         if (bdisp_hw_get_op_cfg(ctx, &cfg))
1006                 return -EINVAL;
1007 
1008         /* Split source in vertical strides (HW constraint) */
1009         for (i = 0; i < MAX_VERTICAL_STRIDES; i++) {
1010                 /* Build RGB/Y node and link it to the previous node */
1011                 bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
1012                                     cfg.dst_nbp == 1 ? BDISP_RGB : BDISP_Y,
1013                                     src_x_offset);
1014                 if (nid)
1015                         ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
1016                 nid++;
1017 
1018                 /* Build additional Cb(Cr) node, link it to the previous one */
1019                 if (cfg.dst_nbp > 1) {
1020                         bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
1021                                             BDISP_CBCR, src_x_offset);
1022                         ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
1023                         nid++;
1024                 }
1025 
1026                 /* Next stride until full width covered */
1027                 src_x_offset += MAX_SRC_WIDTH;
1028                 if (src_x_offset >= ctx->src.crop.width)
1029                         break;
1030         }
1031 
1032         /* Mark last node as the last */
1033         ctx->node[nid - 1]->nip = 0;
1034 
1035         return 0;
1036 }
1037 
1038 /**
1039  * bdisp_hw_save_request
1040  * @ctx:        device context
1041  *
1042  * Save a copy of the request and of the built nodes
1043  *
1044  * RETURNS:
1045  * None
1046  */
1047 static void bdisp_hw_save_request(struct bdisp_ctx *ctx)
1048 {
1049         struct bdisp_node **copy_node = ctx->bdisp_dev->dbg.copy_node;
1050         struct bdisp_request *request = &ctx->bdisp_dev->dbg.copy_request;
1051         struct bdisp_node **node = ctx->node;
1052         int i;
1053 
1054         /* Request copy */
1055         request->src = ctx->src;
1056         request->dst = ctx->dst;
1057         request->hflip = ctx->hflip;
1058         request->vflip = ctx->vflip;
1059         request->nb_req++;
1060 
1061         /* Nodes copy */
1062         for (i = 0; i < MAX_NB_NODE; i++) {
1063                 /* Allocate memory if not done yet */
1064                 if (!copy_node[i]) {
1065                         copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev,
1066                                                     sizeof(*copy_node[i]),
1067                                                     GFP_ATOMIC);
1068                         if (!copy_node[i])
1069                                 return;
1070                 }
1071                 *copy_node[i] = *node[i];
1072         }
1073 }
1074 
1075 /**
1076  * bdisp_hw_update
1077  * @ctx:        device context
1078  *
1079  * Send the request to the HW
1080  *
1081  * RETURNS:
1082  * 0 on success
1083  */
1084 int bdisp_hw_update(struct bdisp_ctx *ctx)
1085 {
1086         int ret;
1087         struct bdisp_dev *bdisp = ctx->bdisp_dev;
1088         struct device *dev = bdisp->dev;
1089         unsigned int node_id;
1090 
1091         dev_dbg(dev, "%s\n", __func__);
1092 
1093         /* build nodes */
1094         ret = bdisp_hw_build_all_nodes(ctx);
1095         if (ret) {
1096                 dev_err(dev, "cannot build nodes (%d)\n", ret);
1097                 return ret;
1098         }
1099 
1100         /* Save a copy of the request */
1101         bdisp_hw_save_request(ctx);
1102 
1103         /* Configure interrupt to 'Last Node Reached for AQ1' */
1104         writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL);
1105         writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0);
1106 
1107         /* Write first node addr */
1108         writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP);
1109 
1110         /* Find and write last node addr : this starts the HW processing */
1111         for (node_id = 0; node_id < MAX_NB_NODE - 1; node_id++) {
1112                 if (!ctx->node[node_id]->nip)
1113                         break;
1114         }
1115         writel(ctx->node_paddr[node_id], bdisp->regs + BLT_AQ1_LNA);
1116 
1117         return 0;
1118 }

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