brintos

brintos / linux-shallow public Read only

0
0
Text · 27.3 KiB · a74e9fd Raw
1119 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) STMicroelectronics SA 20144 * 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           204815 16/* Reset & boot poll config */17#define POLL_RST_MAX            50018#define POLL_RST_DELAY_MS       219 20enum bdisp_target_plan {21	BDISP_RGB,22	BDISP_Y,23	BDISP_CBCR24};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, 0x0063		}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, 0xff77		}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, 0xff91		}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, 0xff105		}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, 0xfc119		}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, 0xfd133		}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, 0xff147		}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, 0x05161		}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, 0xfc175		}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, 0xff189		}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, 0x01203		}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, 0x03217		}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, 0x00237		}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, 0x06251		}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, 0x07265		}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, 0x05279		}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, 0xfc293		}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, 0xfe307		}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, 0x03321		}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, 0x06335		}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, 0x08349		}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_reset360 * @bdisp:      bdisp entity361 *362 * Resets HW363 *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_irq395 * @bdisp:      bdisp entity396 *397 * Read then reset interrupt status398 *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_nodes424 * @ctx:        bdisp context425 *426 * Free node memory427 *428 * RETURNS:429 * None430 */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_nodes442 * @ctx:        bdisp context443 *444 * Allocate dma memory for nodes445 *446 * RETURNS:447 * 0 on success448 */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_filters480 * @dev:        device481 *482 * Free filters memory483 *484 * RETURNS:485 * None486 */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_filters498 * @dev:        device499 *500 * Allocate dma memory for filters501 *502 * RETURNS:503 * 0 on success504 */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_addr544 * @inc:        resize increment545 *546 * Find the horizontal filter table that fits the resize increment547 *548 * RETURNS:549 * table physical address550 */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_addr565 * @inc:        resize increment566 *567 * Find the vertical filter table that fits the resize increment568 *569 * RETURNS:570 * table physical address571 */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_inc586 * @from:       input size587 * @to:         output size588 * @inc:        resize increment in 6.10 format589 *590 * Computes the increment (inverse of scale) in 6.10 format591 *592 * RETURNS:593 * 0 on success594 */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_inc619 * @ctx:        device context620 * @h_inc:      horizontal increment621 * @v_inc:      vertical increment622 *623 * Computes the horizontal & vertical increments (inverse of scale)624 *625 * RETURNS:626 * 0 on success627 */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_cfg650 * @ctx:        device context651 * @c:          operation configuration652 *653 * Check which blitter operations are expected and sets the scaling increments654 *655 * RETURNS:656 * 0 on success657 */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	else700		c->scale = false;701 702	return 0;703}704 705/**706 * bdisp_hw_color_format707 * @pixelformat: v4l2 pixel format708 *709 * v4l2 to bdisp pixel format convert710 *711 * RETURNS:712 * bdisp pixel format713 */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_node746 * @ctx:        device context747 * @cfg:        operation configuration748 * @node:       node to be set749 * @t_plan:     whether the node refers to a RGB/Y or a CbCr plane750 * @src_x_offset: x offset in the source image751 *752 * Build a node753 *754 * RETURNS:755 * None756 */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 = Y800		 * Src2 = CbCr or ColorFill if writing the Y plane801		 * 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		else806			node->ins |= BLT_INS_S2_MEM;807		break;808	case 3:809	default:810		/* Src3 = Y811		 * Src2 = Cb or ColorFill if writing the Y plane812		 * 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		else817			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_nodes985 * @ctx:        device context986 *987 * Build all the nodes for the blitter operation988 *989 * RETURNS:990 * 0 on success991 */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_request1040 * @ctx:        device context1041 *1042 * Save a copy of the request and of the built nodes1043 *1044 * RETURNS:1045 * None1046 */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_update1077 * @ctx:        device context1078 *1079 * Send the request to the HW1080 *1081 * RETURNS:1082 * 0 on success1083 */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}1119