1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) Rockchip Electronics Co., Ltd.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Huang Lee <Putin.li@rock-chips.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #define pr_fmt(fmt) "rga_policy: " fmt
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include "rga_job.h"
11*4882a593Smuzhiyun #include "rga_common.h"
12*4882a593Smuzhiyun #include "rga_hw_config.h"
13*4882a593Smuzhiyun #include "rga_debugger.h"
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #define GET_GCD(n1, n2) \
16*4882a593Smuzhiyun ({ \
17*4882a593Smuzhiyun int i; \
18*4882a593Smuzhiyun int gcd = 0; \
19*4882a593Smuzhiyun for (i = 1; i <= (n1) && i <= (n2); i++) { \
20*4882a593Smuzhiyun if ((n1) % i == 0 && (n2) % i == 0) \
21*4882a593Smuzhiyun gcd = i; \
22*4882a593Smuzhiyun } \
23*4882a593Smuzhiyun gcd; \
24*4882a593Smuzhiyun })
25*4882a593Smuzhiyun #define GET_LCM(n1, n2, gcd) (((n1) * (n2)) / gcd)
26*4882a593Smuzhiyun
rga_set_feature(struct rga_req * rga_base)27*4882a593Smuzhiyun static int rga_set_feature(struct rga_req *rga_base)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun int feature = 0;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun if (rga_base->render_mode == COLOR_FILL_MODE)
32*4882a593Smuzhiyun feature |= RGA_COLOR_FILL;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun if (rga_base->render_mode == COLOR_PALETTE_MODE)
35*4882a593Smuzhiyun feature |= RGA_COLOR_PALETTE;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun if (rga_base->color_key_max > 0 || rga_base->color_key_min > 0)
38*4882a593Smuzhiyun feature |= RGA_COLOR_KEY;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if ((rga_base->alpha_rop_flag >> 1) & 1)
41*4882a593Smuzhiyun feature |= RGA_ROP_CALCULATE;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun if ((rga_base->alpha_rop_flag >> 8) & 1)
44*4882a593Smuzhiyun feature |= RGA_NN_QUANTIZE;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun return feature;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
rga_check_resolution(const struct rga_rect_range * range,int width,int height)49*4882a593Smuzhiyun static bool rga_check_resolution(const struct rga_rect_range *range, int width, int height)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun if (width > range->max.width || height > range->max.height)
52*4882a593Smuzhiyun return false;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (width < range->min.width || height < range->min.height)
55*4882a593Smuzhiyun return false;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun return true;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
rga_check_format(const struct rga_hw_data * data,int rd_mode,int format,int win_num)60*4882a593Smuzhiyun static bool rga_check_format(const struct rga_hw_data *data,
61*4882a593Smuzhiyun int rd_mode, int format, int win_num)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun int i;
64*4882a593Smuzhiyun bool matched = false;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (rd_mode == RGA_RASTER_MODE) {
67*4882a593Smuzhiyun for (i = 0; i < data->win[win_num].num_of_raster_formats; i++) {
68*4882a593Smuzhiyun if (format == data->win[win_num].raster_formats[i]) {
69*4882a593Smuzhiyun matched = true;
70*4882a593Smuzhiyun break;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun } else if (rd_mode == RGA_FBC_MODE) {
74*4882a593Smuzhiyun for (i = 0; i < data->win[win_num].num_of_fbc_formats; i++) {
75*4882a593Smuzhiyun if (format == data->win[win_num].fbc_formats[i]) {
76*4882a593Smuzhiyun matched = true;
77*4882a593Smuzhiyun break;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun } else if (rd_mode == RGA_TILE_MODE) {
81*4882a593Smuzhiyun for (i = 0; i < data->win[win_num].num_of_tile_formats; i++) {
82*4882a593Smuzhiyun if (format == data->win[win_num].tile_formats[i]) {
83*4882a593Smuzhiyun matched = true;
84*4882a593Smuzhiyun break;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun return matched;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
rga_check_align(uint32_t byte_stride_align,uint32_t format,uint16_t w_stride)92*4882a593Smuzhiyun static bool rga_check_align(uint32_t byte_stride_align, uint32_t format, uint16_t w_stride)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun int bit_stride, pixel_stride, align, gcd;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun pixel_stride = rga_get_pixel_stride_from_format(format);
97*4882a593Smuzhiyun if (pixel_stride <= 0)
98*4882a593Smuzhiyun return false;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun bit_stride = pixel_stride * w_stride;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (bit_stride % (byte_stride_align * 8) == 0)
103*4882a593Smuzhiyun return true;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun if (DEBUGGER_EN(MSG)) {
106*4882a593Smuzhiyun gcd = GET_GCD(pixel_stride, byte_stride_align * 8);
107*4882a593Smuzhiyun align = GET_LCM(pixel_stride, byte_stride_align * 8, gcd) / pixel_stride;
108*4882a593Smuzhiyun pr_info("unsupported width stride %d, 0x%x should be %d aligned!",
109*4882a593Smuzhiyun w_stride, format, align);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return false;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
rga_check_src0(const struct rga_hw_data * data,struct rga_img_info_t * src0)115*4882a593Smuzhiyun static bool rga_check_src0(const struct rga_hw_data *data,
116*4882a593Smuzhiyun struct rga_img_info_t *src0)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun if (!rga_check_resolution(&data->input_range, src0->act_w, src0->act_h))
119*4882a593Smuzhiyun return false;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (data == &rga3_data &&
122*4882a593Smuzhiyun !rga_check_resolution(&data->input_range,
123*4882a593Smuzhiyun src0->act_w + src0->x_offset,
124*4882a593Smuzhiyun src0->act_h + src0->y_offset))
125*4882a593Smuzhiyun return false;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (!rga_check_format(data, src0->rd_mode, src0->format, 0))
128*4882a593Smuzhiyun return false;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun if (!rga_check_align(data->byte_stride_align, src0->format, src0->vir_w))
131*4882a593Smuzhiyun return false;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun return true;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
rga_check_src1(const struct rga_hw_data * data,struct rga_img_info_t * src1)136*4882a593Smuzhiyun static bool rga_check_src1(const struct rga_hw_data *data,
137*4882a593Smuzhiyun struct rga_img_info_t *src1)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun if (!rga_check_resolution(&data->input_range, src1->act_w, src1->act_h))
140*4882a593Smuzhiyun return false;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (data == &rga3_data &&
143*4882a593Smuzhiyun !rga_check_resolution(&data->input_range,
144*4882a593Smuzhiyun src1->act_w + src1->x_offset,
145*4882a593Smuzhiyun src1->act_h + src1->y_offset))
146*4882a593Smuzhiyun return false;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (!rga_check_format(data, src1->rd_mode, src1->format, 1))
149*4882a593Smuzhiyun return false;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun if (!rga_check_align(data->byte_stride_align, src1->format, src1->vir_w))
152*4882a593Smuzhiyun return false;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun return true;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
rga_check_dst(const struct rga_hw_data * data,struct rga_img_info_t * dst)157*4882a593Smuzhiyun static bool rga_check_dst(const struct rga_hw_data *data,
158*4882a593Smuzhiyun struct rga_img_info_t *dst)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun if (!rga_check_resolution(&data->output_range, dst->act_w, dst->act_h))
161*4882a593Smuzhiyun return false;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (data == &rga3_data &&
164*4882a593Smuzhiyun !rga_check_resolution(&data->output_range,
165*4882a593Smuzhiyun dst->act_w + dst->x_offset,
166*4882a593Smuzhiyun dst->act_h + dst->y_offset))
167*4882a593Smuzhiyun return false;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun if (!rga_check_format(data, dst->rd_mode, dst->format, 2))
170*4882a593Smuzhiyun return false;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (!rga_check_align(data->byte_stride_align, dst->format, dst->vir_w))
173*4882a593Smuzhiyun return false;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun return true;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
rga_check_scale(const struct rga_hw_data * data,struct rga_req * rga_base)178*4882a593Smuzhiyun static bool rga_check_scale(const struct rga_hw_data *data,
179*4882a593Smuzhiyun struct rga_req *rga_base)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun struct rga_img_info_t *src0 = &rga_base->src;
182*4882a593Smuzhiyun struct rga_img_info_t *dst = &rga_base->dst;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun int sw, sh;
185*4882a593Smuzhiyun int dw, dh;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun sw = src0->act_w;
188*4882a593Smuzhiyun sh = src0->act_h;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun if ((rga_base->sina == 65536 && rga_base->cosa == 0)
191*4882a593Smuzhiyun || (rga_base->sina == -65536 && rga_base->cosa == 0)) {
192*4882a593Smuzhiyun dw = dst->act_h;
193*4882a593Smuzhiyun dh = dst->act_w;
194*4882a593Smuzhiyun } else {
195*4882a593Smuzhiyun dw = dst->act_w;
196*4882a593Smuzhiyun dh = dst->act_h;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (sw > dw) {
200*4882a593Smuzhiyun if ((sw >> data->max_downscale_factor) > dw)
201*4882a593Smuzhiyun return false;
202*4882a593Smuzhiyun } else if (sw < dw) {
203*4882a593Smuzhiyun if ((sw << data->max_upscale_factor) < dw)
204*4882a593Smuzhiyun return false;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (sh > dh) {
208*4882a593Smuzhiyun if ((sh >> data->max_downscale_factor) > dh)
209*4882a593Smuzhiyun return false;
210*4882a593Smuzhiyun } else if (sh < dh) {
211*4882a593Smuzhiyun if ((sh << data->max_upscale_factor) < dh)
212*4882a593Smuzhiyun return false;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun return true;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
rga_job_assign(struct rga_job * job)218*4882a593Smuzhiyun int rga_job_assign(struct rga_job *job)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct rga_img_info_t *src0 = &job->rga_command_base.src;
221*4882a593Smuzhiyun struct rga_img_info_t *src1 = &job->rga_command_base.pat;
222*4882a593Smuzhiyun struct rga_img_info_t *dst = &job->rga_command_base.dst;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun struct rga_req *rga_base = &job->rga_command_base;
225*4882a593Smuzhiyun const struct rga_hw_data *data;
226*4882a593Smuzhiyun struct rga_scheduler_t *scheduler = NULL;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun int feature;
229*4882a593Smuzhiyun int core = RGA_NONE_CORE;
230*4882a593Smuzhiyun int optional_cores = RGA_NONE_CORE;
231*4882a593Smuzhiyun int specified_cores = RGA_NONE_CORE;
232*4882a593Smuzhiyun int i;
233*4882a593Smuzhiyun int min_of_job_count = -1;
234*4882a593Smuzhiyun unsigned long flags;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /* assigned by userspace */
237*4882a593Smuzhiyun if (rga_base->core > RGA_NONE_CORE) {
238*4882a593Smuzhiyun if (rga_base->core > RGA_CORE_MASK) {
239*4882a593Smuzhiyun pr_err("invalid setting core by user\n");
240*4882a593Smuzhiyun goto finish;
241*4882a593Smuzhiyun } else if (rga_base->core & RGA_CORE_MASK)
242*4882a593Smuzhiyun specified_cores = rga_base->core;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun feature = rga_set_feature(rga_base);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* function */
248*4882a593Smuzhiyun for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
249*4882a593Smuzhiyun data = rga_drvdata->scheduler[i]->data;
250*4882a593Smuzhiyun scheduler = rga_drvdata->scheduler[i];
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if ((specified_cores != RGA_NONE_CORE) &&
253*4882a593Smuzhiyun (!(scheduler->core & specified_cores)))
254*4882a593Smuzhiyun continue;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
257*4882a593Smuzhiyun pr_info("start policy on core = %d", scheduler->core);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (scheduler->data->mmu == RGA_MMU &&
260*4882a593Smuzhiyun job->flags & RGA_JOB_UNSUPPORT_RGA_MMU) {
261*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
262*4882a593Smuzhiyun pr_info("RGA2 only support under 4G memory!\n");
263*4882a593Smuzhiyun continue;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if (feature > 0) {
267*4882a593Smuzhiyun if (!(feature & data->feature)) {
268*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
269*4882a593Smuzhiyun pr_info("core = %d, break on feature",
270*4882a593Smuzhiyun scheduler->core);
271*4882a593Smuzhiyun continue;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /* only colorfill need single win (colorpalette?) */
276*4882a593Smuzhiyun if (!(feature & 1)) {
277*4882a593Smuzhiyun if (src1->yrgb_addr > 0) {
278*4882a593Smuzhiyun if ((!(src0->rd_mode & data->win[0].rd_mode)) ||
279*4882a593Smuzhiyun (!(src1->rd_mode & data->win[1].rd_mode)) ||
280*4882a593Smuzhiyun (!(dst->rd_mode & data->win[2].rd_mode))) {
281*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
282*4882a593Smuzhiyun pr_info("core = %d, ABC break on rd_mode",
283*4882a593Smuzhiyun scheduler->core);
284*4882a593Smuzhiyun continue;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun } else {
287*4882a593Smuzhiyun if ((!(src0->rd_mode & data->win[0].rd_mode)) ||
288*4882a593Smuzhiyun (!(dst->rd_mode & data->win[2].rd_mode))) {
289*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
290*4882a593Smuzhiyun pr_info("core = %d, ABB break on rd_mode",
291*4882a593Smuzhiyun scheduler->core);
292*4882a593Smuzhiyun continue;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (!rga_check_scale(data, rga_base)) {
297*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
298*4882a593Smuzhiyun pr_info("core = %d, break on rga_check_scale",
299*4882a593Smuzhiyun scheduler->core);
300*4882a593Smuzhiyun continue;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (!rga_check_src0(data, src0)) {
304*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
305*4882a593Smuzhiyun pr_info("core = %d, break on rga_check_src0",
306*4882a593Smuzhiyun scheduler->core);
307*4882a593Smuzhiyun continue;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (src1->yrgb_addr > 0) {
311*4882a593Smuzhiyun if (!rga_check_src1(data, src1)) {
312*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
313*4882a593Smuzhiyun pr_info("core = %d, break on rga_check_src1",
314*4882a593Smuzhiyun scheduler->core);
315*4882a593Smuzhiyun continue;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (!rga_check_dst(data, dst)) {
321*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
322*4882a593Smuzhiyun pr_info("core = %d, break on rga_check_dst",
323*4882a593Smuzhiyun scheduler->core);
324*4882a593Smuzhiyun continue;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun optional_cores |= scheduler->core;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
331*4882a593Smuzhiyun pr_info("optional_cores = %d\n", optional_cores);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (optional_cores == 0) {
334*4882a593Smuzhiyun core = -1;
335*4882a593Smuzhiyun pr_err("invalid function policy\n");
336*4882a593Smuzhiyun goto finish;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
340*4882a593Smuzhiyun scheduler = rga_drvdata->scheduler[i];
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (optional_cores & scheduler->core) {
343*4882a593Smuzhiyun spin_lock_irqsave(&scheduler->irq_lock, flags);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (scheduler->running_job == NULL) {
346*4882a593Smuzhiyun core = scheduler->core;
347*4882a593Smuzhiyun job->scheduler = scheduler;
348*4882a593Smuzhiyun spin_unlock_irqrestore(&scheduler->irq_lock,
349*4882a593Smuzhiyun flags);
350*4882a593Smuzhiyun break;
351*4882a593Smuzhiyun } else {
352*4882a593Smuzhiyun if ((min_of_job_count == -1) ||
353*4882a593Smuzhiyun (min_of_job_count > scheduler->job_count)) {
354*4882a593Smuzhiyun min_of_job_count = scheduler->job_count;
355*4882a593Smuzhiyun core = scheduler->core;
356*4882a593Smuzhiyun job->scheduler = scheduler;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun spin_unlock_irqrestore(&scheduler->irq_lock, flags);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* TODO: need consider full load */
365*4882a593Smuzhiyun finish:
366*4882a593Smuzhiyun if (DEBUGGER_EN(MSG))
367*4882a593Smuzhiyun pr_info("assign core: %d\n", core);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun return core;
370*4882a593Smuzhiyun }
371