Commit 3bf72d11 authored by Enrico Scholz's avatar Enrico Scholz

Merge branch 'kernel-phy' into 4.14/vm016-next

parents 9debed99 f8a4027f
......@@ -614,11 +614,20 @@ void onsemi_power_put(struct onsemi_core *sensor)
}
EXPORT_SYMBOL_GPL(onsemi_power_put);
#define attribute_typeof(_struct, _attr) __typeof__(&((_struct *)0)->_attr)
#define attribute_types_compatible(_type, _struct, _attr) \
(__builtin_types_compatible_p(attribute_typeof(_struct, _attr), _type *))
#define offsetof_t(_type, _struct, _attr) \
(BUILD_BUG_ON_ZERO(!attribute_types_compatible(_type, _struct, _attr)) + \
offsetof(_struct, _attr))
#define DECL_LIMIT(_reg, _attr) \
{ \
.reg = _reg, \
.name = # _attr, \
.ofs = offsetof(struct onsemi_limits, _attr), \
.ofs = offsetof_t(unsigned long, \
struct onsemi_limits, _attr), \
}
static struct {
......@@ -1299,7 +1308,7 @@ static void onsemi_get_frame_size(struct onsemi_core const *onsemi,
h_size = parm->crop.width;
h_size += parm->hblank;
h_size = clamp_t(unsigned int, h_size,
h_size = clamp_t(unsigned int, (h_size + 1) / 2 * 2,
limits->hlen.min, limits->hlen.max);
v_size = parm->crop.height;
......@@ -1404,6 +1413,7 @@ static void onsemi_params_group_hold(struct onsemi_core *onsemi, bool ena, int *
static void onsemi_params_write_frame(struct onsemi_core *onsemi, int *err)
{
struct onsemi_v4l_parm const *parm = onsemi->v4l_parm;
struct onsemi_businfo const *bus_info = onsemi->active_bus;
unsigned int h_size;
unsigned int v_size;
......@@ -1412,17 +1422,22 @@ static void onsemi_params_write_frame(struct onsemi_core *onsemi, int *err)
onsemi_get_frame_size(onsemi, NULL, &h_size, &v_size);
if (onsemi->ops->hclk_mul_2)
h_size *= 2;
if (onsemi->ops->hclk_mul_2 && bus_info) {
/* HACK: this smells ugly and is based upon experiments with
* the register wizard */
if (bus_info->bus_type == V4L2_MBUS_CSI2 &&
bus_info->bus_width < 4)
h_size *= 2;
}
onsemi_write(err, onsemi, 0x300a, v_size); /* frame_length_line */
onsemi_write(err, onsemi, 0x300c, h_size); /* line_length_pck */
if (onsemi->ops->has_smia_cfg) {
onsemi_write(err, onsemi, 0x034c, /* x_output_size */
parm->frame.width / parm->x_scale);
onsemi_write(err, onsemi, 0x034e, /* y_output_size */
parm->frame.height / parm->y_scale);
/* x_output_size */
onsemi_write(err, onsemi, 0x034c, parm->frame.width);
/* y_output_size */
onsemi_write(err, onsemi, 0x034e, parm->frame.height);
}
}
......@@ -1474,8 +1489,7 @@ static void onsemi_params_write_mipi(struct onsemi_core *onsemi, int *err)
return;
}
onsemi_write(err, onsemi, 0x31ae,
(info->bus_width << 8) | info->bus_width);
onsemi_write(err, onsemi, 0x31ae, (2 << 8) | info->bus_width);
onsemi_update_bits(err, onsemi, 0x301a,
ONSEMI_FLD_RESET_REGISTER_SMIA_DIS |
ONSEMI_FLD_RESET_REGISTER_PARALLEL_EN |
......@@ -3123,6 +3137,118 @@ static int onsemi_calculate_vco(unsigned int *pll_div,
return 0;
}
/**
* Calculates a f_vco so that the maximum bus frequency can be reached
*
*
*/
static unsigned long _onsemi_estimate_vco(struct onsemi_core const *onsemi,
struct onsemi_businfo const *bus_info,
unsigned int bpp)
{
struct onsemi_limits const *limits = onsemi->limits;
unsigned long bus_freq;
unsigned long vco_freq;
bus_freq = bus_info->max_freq;
/* estimate F_vco so that requested bus frequency can be matched */
switch (bus_info->bus_type) {
case V4L2_MBUS_PARALLEL: {
unsigned long max_bus = limits->pix_clk.max;
if (bus_freq == 0 || bus_freq > max_bus)
bus_freq = max_bus;
vco_freq = bus_freq * 12;
break;
}
case V4L2_MBUS_CSI2: {
unsigned long max_vco = limits->pix_clk.max * bpp;
unsigned int bus_width = bus_info->bus_width;
if (bus_freq == 0 || bus_freq >= max_vco / bus_width)
vco_freq = max_vco;
else
vco_freq = bus_freq * bus_width;
break;
}
default:
WARN_ON(1);
return 0;
}
/* adjust F_vco so that it is in a valid range and target frequency
* can be reached */
while (vco_freq > limits->pll_vco.max)
vco_freq /= 2;
return vco_freq;
}
static void _onsemi_calculate_div(struct onsemi_core const *onsemi,
struct onsemi_businfo const *bus_info,
unsigned long freq_vco,
unsigned int bpp,
struct onsemi_pll_cfg *cfg)
{
struct onsemi_limits const *limits = onsemi->limits;
switch (bus_info->bus_type) {
case V4L2_MBUS_PARALLEL:
cfg->vt_sys_div = 1;
cfg->vt_pix_div = 12 / 2;
/* not used */
cfg->op_sys_div = 0;
cfg->op_pix_div = 0;
break;
case V4L2_MBUS_CSI2: {
uint64_t max_f;
/* limit serial output clock */
max_f = limits->f_serial.max;
if (bus_info->max_freq != 0)
max_f = min_t(uint64_t, max_f, bus_info->max_freq);
max_f *= bus_info->bus_width;
cfg->op_sys_div = 1;
while (freq_vco / cfg->op_sys_div > max_f)
cfg->op_sys_div *= 2;
dev_dbg(onsemi->dev, " vco=%lu, max_op=%llu -> div=%u\n",
freq_vco, max_f, cfg->op_sys_div);
/* limit pixel clock */
max_f = limits->pix_clk.max;
max_f *= bpp / 2;
cfg->vt_sys_div = cfg->op_sys_div;
while (freq_vco / cfg->vt_sys_div > max_f) {
cfg->op_sys_div *= 2;
cfg->vt_sys_div *= 2;
}
/* f_pix and f_op have a fixed 2:1 ratio */
cfg->vt_pix_div = bpp / 2;
cfg->op_pix_div = bpp;
dev_dbg(onsemi->dev, " vco=%lu, max_vt=%llu -> vt_div=%u*%u, op_div=%u*%u\n",
freq_vco, max_f,
cfg->vt_sys_div, cfg->vt_pix_div,
cfg->op_sys_div, cfg->op_pix_div);
break;
}
default:
BUG();
}
}
int onsemi_calculate_pll(struct onsemi_core const *onsemi,
struct onsemi_businfo const *bus_info,
unsigned int bpp,
......@@ -3138,7 +3264,6 @@ int onsemi_calculate_pll(struct onsemi_core const *onsemi,
.op_speed = 1,
};
unsigned long vco_freq;
unsigned long bus_freq;
if (WARN_ON(!bus_info))
return -EPIPE;
......@@ -3154,33 +3279,7 @@ int onsemi_calculate_pll(struct onsemi_core const *onsemi,
bus_info->bus_type, bus_info->max_freq, bus_info->bus_width,
bpp);
bus_freq = bus_info->max_freq;
/* estimate F_vco so that requested bus frequency can be matched */
switch (bus_info->bus_type) {
case V4L2_MBUS_PARALLEL:
if (bus_freq == 0)
bus_freq = onsemi->limits->pix_clk.max;
vco_freq = bus_freq * 12;
break;
case V4L2_MBUS_CSI2:
if (bus_freq == 0)
vco_freq = onsemi->limits->pix_clk.max * bpp;
else
vco_freq = bus_freq * bus_info->bus_width;
break;
default:
WARN_ON(1);
return -EINVAL;
}
/* adjust F_vco so that it is in a valid range and target frequency
* can be reached */
while (vco_freq > onsemi->limits->pll_vco.max)
vco_freq /= 2;
vco_freq = _onsemi_estimate_vco(onsemi, bus_info, bpp);
rc = onsemi_calculate_vco(&cfg.pre_pll_div, &cfg.pre_pll_mul,
limits, onsemi->ext_clk_freq, vco_freq);
......@@ -3190,45 +3289,22 @@ int onsemi_calculate_pll(struct onsemi_core const *onsemi,
freq.ext = onsemi->ext_clk_freq;
freq.vco = freq.ext * cfg.pre_pll_mul / cfg.pre_pll_div;
switch (bus_info->bus_type) {
case V4L2_MBUS_PARALLEL:
cfg.vt_sys_div = 1;
cfg.op_sys_div = 1;
break;
case V4L2_MBUS_CSI2:
cfg.op_sys_div = 1;
while (freq.vco / cfg.op_sys_div >
limits->f_serial.max * bus_info->bus_width)
cfg.op_sys_div *= 2;
cfg.vt_sys_div = cfg.op_sys_div;
while (freq.vco / cfg.vt_sys_div >
onsemi->limits->pix_clk.max * bpp / bus_info->bus_width) {
cfg.op_sys_div *= 2;
cfg.vt_sys_div *= 2;
}
break;
default:
BUG();
}
_onsemi_calculate_div(onsemi, bus_info, freq.vco, bpp, &cfg);
switch (bus_info->bus_type) {
case V4L2_MBUS_CSI2:
cfg.vt_pix_div = bpp / bus_info->bus_width;
cfg.op_pix_div = bpp;
use_op_clk = true;
/* TODO: where is this '/ 2' is coming from? It has been
* added because csi2_dphy_init() in the imx6 csi driver
* expects this scaling. */
freq.link_freq = freq.vco / cfg.op_sys_div / 2;
if (bus_info->bus_width > 2)
freq.link_freq *= bus_info->bus_width / 2;
break;
case V4L2_MBUS_PARALLEL:
cfg.vt_pix_div = 12 / 2;
cfg.op_pix_div = 12; /* not used */
use_op_clk = false;
freq.link_freq = freq.vco / cfg.vt_sys_div / cfg.vt_pix_div;
break;
......
......@@ -71,8 +71,8 @@ struct onsemi_limits {
struct onsemi_range x;
struct onsemi_range y;
unsigned int hblank_min;
unsigned int vblank_min;
unsigned long hblank_min;
unsigned long vblank_min;
struct onsemi_range hlen;
struct onsemi_range vlen;
......
......@@ -593,6 +593,7 @@ static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
&sink->pads[0], MEDIA_LNK_FL_ENABLED);
if (rc < 0 && rc != -ENOIOCTLCMD) {
v4l2_err(&csi2dev->v4l2_dev, "failed to link pads: %d\n", rc);
csi2dev->sensor_sd = NULL;
goto out;
}
......
......@@ -954,7 +954,7 @@ static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev)
if (csi_dev->csi_mipi_mode == true) {
cr1 = csi_read(csi_dev, CSI_CSICR1);
cr1 &= ~BIT_GCLK_MODE;
csi_write(csi_dev, cr1, CSI_CSICR1);
cr1 &= ~BIT_PIXEL_BIT;
cr18 = csi_read(csi_dev, CSI_CSICR18);
cr18 &= ~BIT_MIPI_DATA_FORMAT_MASK;
......@@ -978,6 +978,7 @@ static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev)
case V4L2_PIX_FMT_SRGGB10:
case V4L2_PIX_FMT_Y10:
cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
cr1 |= BIT_PIXEL_BIT;
break;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGRBG12:
......@@ -985,12 +986,14 @@ static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev)
case V4L2_PIX_FMT_SRGGB12:
case V4L2_PIX_FMT_Y12:
cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
cr1 |= BIT_PIXEL_BIT;
break;
default:
pr_debug(" fmt not supported\n");
return -EINVAL;
}
csi_write(csi_dev, cr1, CSI_CSICR1);
csi_write(csi_dev, cr18, CSI_CSICR18);
}
return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment