blob: 417feb9f1f7931dff96f2222ae9e2e5df838c431 [file] [log] [blame]
Archit Taneja44687b22013-12-12 05:35:57 -03001/*
2 * Scaler library
3 *
4 * Copyright (c) 2013 Texas Instruments Inc.
5 *
6 * David Griego, <dagriego@biglakesoftware.com>
7 * Dale Farnsworth, <dale@farnsworth.org>
8 * Archit Taneja, <archit@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 */
14
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19
20#include "sc.h"
Archit Taneja0df20f92013-12-12 05:35:58 -030021#include "sc_coeff.h"
Archit Taneja44687b22013-12-12 05:35:57 -030022
23void sc_set_regs_bypass(struct sc_data *sc, u32 *sc_reg0)
24{
25 *sc_reg0 |= CFG_SC_BYPASS;
26}
27
28void sc_dump_regs(struct sc_data *sc)
29{
30 struct device *dev = &sc->pdev->dev;
31
32 u32 read_reg(struct sc_data *sc, int offset)
33 {
34 return ioread32(sc->base + offset);
35 }
36
37#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(sc, CFG_##r))
38
39 DUMPREG(SC0);
40 DUMPREG(SC1);
41 DUMPREG(SC2);
42 DUMPREG(SC3);
43 DUMPREG(SC4);
44 DUMPREG(SC5);
45 DUMPREG(SC6);
46 DUMPREG(SC8);
47 DUMPREG(SC9);
48 DUMPREG(SC10);
49 DUMPREG(SC11);
50 DUMPREG(SC12);
51 DUMPREG(SC13);
52 DUMPREG(SC17);
53 DUMPREG(SC18);
54 DUMPREG(SC19);
55 DUMPREG(SC20);
56 DUMPREG(SC21);
57 DUMPREG(SC22);
58 DUMPREG(SC23);
59 DUMPREG(SC24);
60 DUMPREG(SC25);
61
62#undef DUMPREG
63}
64
Archit Taneja0df20f92013-12-12 05:35:58 -030065/*
66 * set the horizontal scaler coefficients according to the ratio of output to
67 * input widths, after accounting for up to two levels of decimation
68 */
69void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w,
70 unsigned int dst_w)
71{
72 int sixteenths;
73 int idx;
74 int i, j;
75 u16 *coeff_h = addr;
76 const u16 *cp;
77
78 if (dst_w > src_w) {
79 idx = HS_UP_SCALE;
80 } else {
81 if ((dst_w << 1) < src_w)
82 dst_w <<= 1; /* first level decimation */
83 if ((dst_w << 1) < src_w)
84 dst_w <<= 1; /* second level decimation */
85
86 if (dst_w == src_w) {
87 idx = HS_LE_16_16_SCALE;
88 } else {
89 sixteenths = (dst_w << 4) / src_w;
90 if (sixteenths < 8)
91 sixteenths = 8;
92 idx = HS_LT_9_16_SCALE + sixteenths - 8;
93 }
94 }
95
96 if (idx == sc->hs_index)
97 return;
98
99 cp = scaler_hs_coeffs[idx];
100
101 for (i = 0; i < SC_NUM_PHASES * 2; i++) {
102 for (j = 0; j < SC_H_NUM_TAPS; j++)
103 *coeff_h++ = *cp++;
104 /*
105 * for each phase, the scaler expects space for 8 coefficients
106 * in it's memory. For the horizontal scaler, we copy the first
107 * 7 coefficients and skip the last slot to move to the next
108 * row to hold coefficients for the next phase
109 */
110 coeff_h += SC_NUM_TAPS_MEM_ALIGN - SC_H_NUM_TAPS;
111 }
112
113 sc->hs_index = idx;
114
115 sc->load_coeff_h = true;
116}
117
118/*
119 * set the vertical scaler coefficients according to the ratio of output to
120 * input heights
121 */
122void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h,
123 unsigned int dst_h)
124{
125 int sixteenths;
126 int idx;
127 int i, j;
128 u16 *coeff_v = addr;
129 const u16 *cp;
130
131 if (dst_h > src_h) {
132 idx = VS_UP_SCALE;
133 } else if (dst_h == src_h) {
134 idx = VS_1_TO_1_SCALE;
135 } else {
136 sixteenths = (dst_h << 4) / src_h;
137 if (sixteenths < 8)
138 sixteenths = 8;
139 idx = VS_LT_9_16_SCALE + sixteenths - 8;
140 }
141
142 if (idx == sc->vs_index)
143 return;
144
145 cp = scaler_vs_coeffs[idx];
146
147 for (i = 0; i < SC_NUM_PHASES * 2; i++) {
148 for (j = 0; j < SC_V_NUM_TAPS; j++)
149 *coeff_v++ = *cp++;
150 /*
151 * for the vertical scaler, we copy the first 5 coefficients and
152 * skip the last 3 slots to move to the next row to hold
153 * coefficients for the next phase
154 */
155 coeff_v += SC_NUM_TAPS_MEM_ALIGN - SC_V_NUM_TAPS;
156 }
157
158 sc->vs_index = idx;
159 sc->load_coeff_v = true;
160}
161
Archit Taneja44687b22013-12-12 05:35:57 -0300162struct sc_data *sc_create(struct platform_device *pdev)
163{
164 struct sc_data *sc;
165
166 dev_dbg(&pdev->dev, "sc_create\n");
167
168 sc = devm_kzalloc(&pdev->dev, sizeof(*sc), GFP_KERNEL);
169 if (!sc) {
170 dev_err(&pdev->dev, "couldn't alloc sc_data\n");
171 return ERR_PTR(-ENOMEM);
172 }
173
174 sc->pdev = pdev;
175
176 sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sc");
177 if (!sc->res) {
178 dev_err(&pdev->dev, "missing platform resources data\n");
179 return ERR_PTR(-ENODEV);
180 }
181
182 sc->base = devm_ioremap_resource(&pdev->dev, sc->res);
183 if (!sc->base) {
184 dev_err(&pdev->dev, "failed to ioremap\n");
185 return ERR_PTR(-ENOMEM);
186 }
187
188 return sc;
189}