File Index
Files and directories
Sign in
FILE

bdisp-hw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/st/sti/bdisp/bdisp-hw.c C
   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
  20enum bdisp_target_plan {
  21	BDISP_RGB,
  22	BDISP_Y,
  23	BDISP_CBCR
  24};
  25
  26struct 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
  43struct 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
  50static 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
 224static 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
 355static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];
 356static 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 */
 367int 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 */
 402int 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 */
 431void 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 */
 449int 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 */
 487void 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 */
 505int 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 */
 551static 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 */
 572static 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 */
 595static 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 */
 628static 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 */
 658static 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 */
 714static 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 */
 757static 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 */
 992static 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 */
1047static 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 */
1084int 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}
~/ Read-only file preview.