return 0;
}
+static const char *module_type_str(struct mgb4_dev *mgbdev)
+{
+ if (MGB4_IS_FPDL3(mgbdev))
+ return "FPDL3";
+ else if (MGB4_IS_GMSL3(mgbdev))
+ return "GMSL3";
+ else if (MGB4_IS_GMSL1(mgbdev))
+ return "GMSL1";
+ else
+ return "UNKNOWN";
+}
+
static int get_module_version(struct mgb4_dev *mgbdev)
{
struct device *dev = &mgbdev->pdev->dev;
}
mgbdev->module_version = ~((u32)version) & 0xff;
- if (!(MGB4_IS_FPDL3(mgbdev) || MGB4_IS_GMSL(mgbdev))) {
+ if (!(MGB4_IS_FPDL3(mgbdev) ||
+ MGB4_IS_GMSL3(mgbdev) ||
+ MGB4_IS_GMSL1(mgbdev))) {
dev_err(dev, "unknown module type\n");
return -EINVAL;
}
fw_version = mgb4_read_reg(&mgbdev->video, 0xC4) >> 24;
if ((MGB4_IS_FPDL3(mgbdev) && fw_version != 1) ||
- (MGB4_IS_GMSL(mgbdev) && fw_version != 2)) {
+ (MGB4_IS_GMSL3(mgbdev) && fw_version != 2) ||
+ (MGB4_IS_GMSL1(mgbdev) && fw_version != 3)) {
dev_err(dev, "module/firmware type mismatch\n");
return -EINVAL;
}
- dev_info(dev, "%s module detected\n",
- MGB4_IS_FPDL3(mgbdev) ? "FPDL3" : "GMSL");
+ dev_info(dev, "%s module detected\n", module_type_str(mgbdev));
return 0;
}
#define MGB4_VIN_DEVICES 2
#define MGB4_VOUT_DEVICES 2
-#define MGB4_IS_GMSL(mgbdev) \
+#define MGB4_IS_GMSL1(mgbdev) \
+ (((mgbdev)->module_version >> 4) == 6)
+#define MGB4_IS_GMSL3(mgbdev) \
((((mgbdev)->module_version >> 4) >= 2) && \
(((mgbdev)->module_version >> 4) <= 4))
#define MGB4_IS_FPDL3(mgbdev) \
(((mgbdev)->module_version >> 4) == 1)
#define MGB4_HAS_VOUT(mgbdev) \
- ((((mgbdev)->module_version >> 4) >= 1) && \
- (((mgbdev)->module_version >> 4) <= 3))
+ (((((mgbdev)->module_version >> 4) >= 1) && \
+ (((mgbdev)->module_version >> 4) <= 3)) || \
+ ((((mgbdev)->module_version >> 4) == 6)))
struct mgb4_dma_channel {
struct dma_chan *chan;
extern struct attribute *mgb4_pci_attrs[];
extern struct attribute *mgb4_fpdl3_in_attrs[];
-extern struct attribute *mgb4_gmsl_in_attrs[];
+extern struct attribute *mgb4_gmsl3_in_attrs[];
+extern struct attribute *mgb4_gmsl1_in_attrs[];
extern struct attribute *mgb4_fpdl3_out_attrs[];
-extern struct attribute *mgb4_gmsl_out_attrs[];
+extern struct attribute *mgb4_gmsl3_out_attrs[];
+extern struct attribute *mgb4_gmsl1_out_attrs[];
#endif
u32 config;
int ret;
- i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49;
- i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03;
- i2c_single_val = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02;
- i2c_dual_val = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00;
+ if (MGB4_IS_GMSL1(mgbdev))
+ return sprintf(buf, "0\n");
+
+ i2c_reg = MGB4_IS_GMSL3(mgbdev) ? 0x1CE : 0x49;
+ i2c_mask = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x03;
+ i2c_single_val = MGB4_IS_GMSL3(mgbdev) ? 0x00 : 0x02;
+ i2c_dual_val = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x00;
mutex_lock(&mgbdev->i2c_lock);
ret = mgb4_i2c_read_byte(&vindev->deser, i2c_reg);
if (ret)
return ret;
+ if (MGB4_IS_GMSL1(mgbdev))
+ return val ? -EINVAL : count;
+
switch (val) {
case 0: /* single */
fpga_data = 0;
- i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02;
+ i2c_data = MGB4_IS_GMSL3(mgbdev) ? 0x00 : 0x02;
break;
case 1: /* dual */
fpga_data = 1U << 9;
- i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00;
+ i2c_data = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x00;
break;
default:
return -EINVAL;
}
- i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49;
- i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03;
+ i2c_reg = MGB4_IS_GMSL3(mgbdev) ? 0x1CE : 0x49;
+ i2c_mask = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x03;
mutex_lock(&mgbdev->i2c_lock);
ret = mgb4_i2c_mask_byte(&vindev->deser, i2c_reg, i2c_mask, i2c_data);
return -EIO;
mgb4_mask_reg(&mgbdev->video, vindev->config->regs.config, 1U << 9,
fpga_data);
- if (MGB4_IS_GMSL(mgbdev)) {
+ if (MGB4_IS_GMSL3(mgbdev)) {
/* reset input link */
mutex_lock(&mgbdev->i2c_lock);
ret = mgb4_i2c_mask_byte(&vindev->deser, 0x10, 1U << 5, 1U << 5);
NULL
};
-struct attribute *mgb4_gmsl_in_attrs[] = {
+struct attribute *mgb4_gmsl3_in_attrs[] = {
&dev_attr_input_id.attr,
&dev_attr_link_status.attr,
&dev_attr_stream_status.attr,
&dev_attr_gmsl_fec.attr,
NULL
};
+
+struct attribute *mgb4_gmsl1_in_attrs[] = {
+ &dev_attr_input_id.attr,
+ &dev_attr_link_status.attr,
+ &dev_attr_stream_status.attr,
+ &dev_attr_video_width.attr,
+ &dev_attr_video_height.attr,
+ &dev_attr_hsync_status.attr,
+ &dev_attr_vsync_status.attr,
+ &dev_attr_oldi_lane_width.attr,
+ &dev_attr_color_mapping.attr,
+ &dev_attr_hsync_gap_length.attr,
+ &dev_attr_vsync_gap_length.attr,
+ &dev_attr_pclk_frequency.attr,
+ &dev_attr_hsync_width.attr,
+ &dev_attr_vsync_width.attr,
+ &dev_attr_hback_porch.attr,
+ &dev_attr_hfront_porch.attr,
+ &dev_attr_vback_porch.attr,
+ &dev_attr_vfront_porch.attr,
+ &dev_attr_frequency_range.attr,
+ NULL
+};
{
struct video_device *vdev = to_video_device(dev);
struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
+ struct mgb4_dev *mgbdev = voutdev->mgbdev;
unsigned long val;
int ret;
unsigned int dp;
return -EBUSY;
}
- dp = (val > 50000) ? 1 : 0;
+ dp = (MGB4_IS_FPDL3(mgbdev) && val > 50000) ? 1 : 0;
voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, val >> dp) << dp;
-
- mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.config,
- 0x10, dp << 4);
- mutex_lock(&voutdev->mgbdev->i2c_lock);
- ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6, ((~dp) & 1) << 6);
- mutex_unlock(&voutdev->mgbdev->i2c_lock);
+ mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0x10,
+ dp << 4);
+ if (MGB4_IS_FPDL3(mgbdev)) {
+ mutex_lock(&mgbdev->i2c_lock);
+ ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6,
+ ((~dp) & 1) << 6);
+ mutex_unlock(&mgbdev->i2c_lock);
+ }
mutex_unlock(voutdev->vdev.lock);
NULL
};
-struct attribute *mgb4_gmsl_out_attrs[] = {
+struct attribute *mgb4_gmsl3_out_attrs[] = {
&dev_attr_output_id.attr,
&dev_attr_video_source.attr,
&dev_attr_display_width.attr,
&dev_attr_frame_rate.attr,
NULL
};
+
+struct attribute *mgb4_gmsl1_out_attrs[] = {
+ &dev_attr_output_id.attr,
+ &dev_attr_video_source.attr,
+ &dev_attr_display_width.attr,
+ &dev_attr_display_height.attr,
+ &dev_attr_frame_rate.attr,
+ &dev_attr_hsync_polarity.attr,
+ &dev_attr_vsync_polarity.attr,
+ &dev_attr_de_polarity.attr,
+ &dev_attr_pclk_frequency.attr,
+ &dev_attr_hsync_width.attr,
+ &dev_attr_vsync_width.attr,
+ &dev_attr_hback_porch.attr,
+ &dev_attr_hfront_porch.attr,
+ &dev_attr_vback_porch.attr,
+ &dev_attr_vfront_porch.attr,
+ NULL
+};
#include "mgb4_vin.h"
ATTRIBUTE_GROUPS(mgb4_fpdl3_in);
-ATTRIBUTE_GROUPS(mgb4_gmsl_in);
+ATTRIBUTE_GROUPS(mgb4_gmsl3_in);
+ATTRIBUTE_GROUPS(mgb4_gmsl1_in);
static const struct mgb4_vin_config vin_cfg[] = {
{0, 0, 0, 6, {0x10, 0x00, 0x04, 0x08, 0x1C, 0x14, 0x18, 0x20, 0x24, 0x28, 0xE8}},
{I2C_BOARD_INFO("deserializer2", 0x36)},
};
-static const struct i2c_board_info gmsl_deser_info[] = {
+static const struct i2c_board_info gmsl3_deser_info[] = {
{I2C_BOARD_INFO("deserializer1", 0x4C)},
{I2C_BOARD_INFO("deserializer2", 0x2A)},
};
+static const struct i2c_board_info gmsl1_deser_info[] = {
+ {I2C_BOARD_INFO("deserializer1", 0x2C)},
+ {I2C_BOARD_INFO("deserializer2", 0x6C)},
+};
+
static const struct mgb4_i2c_kv fpdl3_i2c[] = {
{0x06, 0xFF, 0x04}, {0x07, 0xFF, 0x01}, {0x45, 0xFF, 0xE8},
{0x49, 0xFF, 0x00}, {0x34, 0xFF, 0x00}, {0x23, 0xFF, 0x00}
};
-static const struct mgb4_i2c_kv gmsl_i2c[] = {
+static const struct mgb4_i2c_kv gmsl3_i2c[] = {
{0x01, 0x03, 0x03}, {0x300, 0x0C, 0x0C}, {0x03, 0xC0, 0xC0},
{0x1CE, 0x0E, 0x0E}, {0x11, 0x05, 0x00}, {0x05, 0xC0, 0x40},
{0x307, 0x0F, 0x00}, {0xA0, 0x03, 0x00}, {0x3E0, 0x07, 0x07},
{0x308, 0x01, 0x01}, {0x10, 0x20, 0x20}, {0x300, 0x40, 0x40}
};
+static const struct mgb4_i2c_kv gmsl1_i2c[] = {
+};
+
static const struct v4l2_dv_timings_cap video_timings_cap = {
.type = V4L2_DV_BT_656_1120,
.bt = {
static int deser_init(struct mgb4_vin_dev *vindev, int id)
{
- int rv, addr_size;
- size_t values_count;
- const struct mgb4_i2c_kv *values;
- const struct i2c_board_info *info;
+ int rv, addr_size = 0;
+ size_t count = 0;
+ const struct mgb4_i2c_kv *values = NULL;
+ const struct i2c_board_info *info = NULL;
struct device *dev = &vindev->mgbdev->pdev->dev;
- if (MGB4_IS_GMSL(vindev->mgbdev)) {
- info = &gmsl_deser_info[id];
+ if (MGB4_IS_GMSL3(vindev->mgbdev)) {
+ info = &gmsl3_deser_info[id];
addr_size = 16;
- values = gmsl_i2c;
- values_count = ARRAY_SIZE(gmsl_i2c);
- } else {
+ values = gmsl3_i2c;
+ count = ARRAY_SIZE(gmsl3_i2c);
+ } else if (MGB4_IS_FPDL3(vindev->mgbdev)) {
info = &fpdl3_deser_info[id];
addr_size = 8;
values = fpdl3_i2c;
- values_count = ARRAY_SIZE(fpdl3_i2c);
+ count = ARRAY_SIZE(fpdl3_i2c);
+ } else if (MGB4_IS_GMSL1(vindev->mgbdev)) {
+ info = &gmsl1_deser_info[id];
+ addr_size = 8;
+ values = gmsl1_i2c;
+ count = ARRAY_SIZE(gmsl1_i2c);
+ } else {
+ return -EINVAL;
}
rv = mgb4_i2c_init(&vindev->deser, vindev->mgbdev->i2c_adap, info,
dev_err(dev, "failed to create deserializer\n");
return rv;
}
- rv = mgb4_i2c_configure(&vindev->deser, values, values_count);
+ rv = mgb4_i2c_configure(&vindev->deser, values, count);
if (rv < 0) {
dev_err(dev, "failed to configure deserializer\n");
goto err_i2c_dev;
{
struct mgb4_regs *video = &vindev->mgbdev->video;
const struct mgb4_vin_regs *regs = &vindev->config->regs;
+ int dp = MGB4_IS_GMSL1(vindev->mgbdev) ? 0 : 1;
mgb4_write_reg(video, regs->config, 0x00000001);
mgb4_write_reg(video, regs->sync, 0x03E80002);
mgb4_write_reg(video, regs->padding, 0x00000000);
- mgb4_write_reg(video, regs->config, 1U << 9);
+ mgb4_write_reg(video, regs->config, dp << 9);
}
static void create_debugfs(struct mgb4_vin_dev *vindev)
#endif
}
+static const struct attribute_group **module_groups(struct mgb4_dev *mgbdev)
+{
+ if (MGB4_IS_FPDL3(mgbdev))
+ return mgb4_fpdl3_in_groups;
+ else if (MGB4_IS_GMSL3(mgbdev))
+ return mgb4_gmsl3_in_groups;
+ else if (MGB4_IS_GMSL1(mgbdev))
+ return mgb4_gmsl1_in_groups;
+ else
+ return NULL;
+}
+
struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id)
{
int rv;
- const struct attribute_group **groups;
struct mgb4_vin_dev *vindev;
struct pci_dev *pdev = mgbdev->pdev;
struct device *dev = &pdev->dev;
INIT_WORK(&vindev->dma_work, dma_transfer);
INIT_WORK(&vindev->err_work, signal_change);
- /* IRQ callback */
+ /* IRQ callbacks */
vin_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->vin_irq);
rv = request_irq(vin_irq, vin_handler, 0, "mgb4-vin", vindev);
if (rv) {
dev_err(dev, "failed to register vin irq handler\n");
goto err_alloc;
}
- /* Error IRQ callback */
err_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->err_irq);
rv = request_irq(err_irq, err_handler, 0, "mgb4-err", vindev);
if (rv) {
}
/* Module sysfs attributes */
- groups = MGB4_IS_GMSL(mgbdev)
- ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups;
- rv = device_add_groups(&vindev->vdev.dev, groups);
+ rv = device_add_groups(&vindev->vdev.dev, module_groups(mgbdev));
if (rv) {
dev_err(dev, "failed to create sysfs attributes\n");
goto err_video_dev;
void mgb4_vin_free(struct mgb4_vin_dev *vindev)
{
- const struct attribute_group **groups;
int vin_irq = xdma_get_user_irq(vindev->mgbdev->xdev,
vindev->config->vin_irq);
int err_irq = xdma_get_user_irq(vindev->mgbdev->xdev,
free_irq(vin_irq, vindev);
free_irq(err_irq, vindev);
- groups = MGB4_IS_GMSL(vindev->mgbdev)
- ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups;
- device_remove_groups(&vindev->vdev.dev, groups);
+ device_remove_groups(&vindev->vdev.dev, module_groups(vindev->mgbdev));
mgb4_i2c_free(&vindev->deser);
video_unregister_device(&vindev->vdev);
#include "mgb4_vout.h"
ATTRIBUTE_GROUPS(mgb4_fpdl3_out);
-ATTRIBUTE_GROUPS(mgb4_gmsl_out);
+ATTRIBUTE_GROUPS(mgb4_gmsl3_out);
+ATTRIBUTE_GROUPS(mgb4_gmsl1_out);
static const struct mgb4_vout_config vout_cfg[] = {
{0, 0, 8, {0x78, 0x60, 0x64, 0x68, 0x74, 0x6C, 0x70, 0x7C, 0xE0}},
{I2C_BOARD_INFO("serializer2", 0x16)},
};
+static const struct i2c_board_info gmsl1_ser_info[] = {
+ {I2C_BOARD_INFO("serializer1", 0x24)},
+ {I2C_BOARD_INFO("serializer2", 0x22)},
+};
+
static const struct mgb4_i2c_kv fpdl3_i2c[] = {
{0x05, 0xFF, 0x04}, {0x06, 0xFF, 0x01}, {0xC2, 0xFF, 0x80}
};
+static const struct mgb4_i2c_kv gmsl1_i2c[] = {
+};
+
static const struct v4l2_dv_timings_cap video_timings_cap = {
.type = V4L2_DV_BT_656_1120,
.bt = {
static int ser_init(struct mgb4_vout_dev *voutdev, int id)
{
- int rv;
- const struct i2c_board_info *info = &fpdl3_ser_info[id];
struct mgb4_i2c_client *ser = &voutdev->ser;
struct device *dev = &voutdev->mgbdev->pdev->dev;
+ const struct i2c_board_info *info = NULL;
+ const struct mgb4_i2c_kv *values = NULL;
+ size_t count = 0;
+ int rv;
+
+ if (MGB4_IS_FPDL3(voutdev->mgbdev)) {
+ info = &fpdl3_ser_info[id];
+ values = fpdl3_i2c;
+ count = ARRAY_SIZE(fpdl3_i2c);
+ } else if (MGB4_IS_GMSL1(voutdev->mgbdev)) {
+ info = &gmsl1_ser_info[id];
+ values = gmsl1_i2c;
+ count = ARRAY_SIZE(gmsl1_i2c);
+ }
- if (MGB4_IS_GMSL(voutdev->mgbdev))
+ if (!info)
return 0;
rv = mgb4_i2c_init(ser, voutdev->mgbdev->i2c_adap, info, 8);
dev_err(dev, "failed to create serializer\n");
return rv;
}
- rv = mgb4_i2c_configure(ser, fpdl3_i2c, ARRAY_SIZE(fpdl3_i2c));
+ rv = mgb4_i2c_configure(ser, values, count);
if (rv < 0) {
dev_err(dev, "failed to configure serializer\n");
goto err_i2c_dev;
{
struct mgb4_regs *video = &voutdev->mgbdev->video;
const struct mgb4_vout_regs *regs = &voutdev->config->regs;
+ int dp = MGB4_IS_GMSL1(voutdev->mgbdev) ? 0 : 1;
+ u32 source = (voutdev->config->id + MGB4_VIN_DEVICES) << 2;
- mgb4_write_reg(video, regs->config, 0x00000011);
+ mgb4_write_reg(video, regs->config, 0x00000001);
mgb4_write_reg(video, regs->resolution, (1280 << 16) | 640);
mgb4_write_reg(video, regs->hsync, 0x00283232);
mgb4_write_reg(video, regs->vsync, 0x40141F1E);
mgb4_write_reg(video, regs->frame_limit, MGB4_HW_FREQ / 60);
mgb4_write_reg(video, regs->padding, 0x00000000);
- voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 61150 >> 1) << 1;
+ voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 61150 >> dp) << dp;
- mgb4_write_reg(video, regs->config,
- (voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4);
+ mgb4_write_reg(video, regs->config, source | dp << 4);
}
static void create_debugfs(struct mgb4_vout_dev *voutdev)
#endif
}
+static const struct attribute_group **module_groups(struct mgb4_dev *mgbdev)
+{
+ if (MGB4_IS_FPDL3(mgbdev))
+ return mgb4_fpdl3_out_groups;
+ else if (MGB4_IS_GMSL3(mgbdev))
+ return mgb4_gmsl3_out_groups;
+ else if (MGB4_IS_GMSL1(mgbdev))
+ return mgb4_gmsl1_out_groups;
+ else
+ return NULL;
+}
+
struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id)
{
int rv, irq;
- const struct attribute_group **groups;
struct mgb4_vout_dev *voutdev;
struct pci_dev *pdev = mgbdev->pdev;
struct device *dev = &pdev->dev;
}
/* Module sysfs attributes */
- groups = MGB4_IS_GMSL(mgbdev)
- ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups;
- rv = device_add_groups(&voutdev->vdev.dev, groups);
+ rv = device_add_groups(&voutdev->vdev.dev, module_groups(mgbdev));
if (rv) {
dev_err(dev, "failed to create sysfs attributes\n");
goto err_video_dev;
void mgb4_vout_free(struct mgb4_vout_dev *voutdev)
{
- const struct attribute_group **groups;
int irq = xdma_get_user_irq(voutdev->mgbdev->xdev, voutdev->config->irq);
free_irq(irq, voutdev);
-
- groups = MGB4_IS_GMSL(voutdev->mgbdev)
- ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups;
- device_remove_groups(&voutdev->vdev.dev, groups);
-
+ device_remove_groups(&voutdev->vdev.dev, module_groups(voutdev->mgbdev));
mgb4_i2c_free(&voutdev->ser);
video_unregister_device(&voutdev->vdev);
v4l2_device_unregister(&voutdev->v4l2dev);