Commit 9c3e59de authored by Todor Tomov's avatar Todor Tomov Committed by Mauro Carvalho Chehab

media: camss: Add 8x96 resources

Add structs with 8x96 resources. As the number of CSIPHY, CSID
and VFE hardware modules is different on 8x16 and 8x96 select
the number at runtime and allocate needed structures
dynamically.
Signed-off-by: default avatarTodor Tomov <todor.tomov@linaro.org>
Signed-off-by: default avatarHans Verkuil <hansverk@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 21a3f6e5
......@@ -219,7 +219,7 @@ static irqreturn_t csid_isr(int irq, void *dev)
*/
static int csid_set_clock_rates(struct csid_device *csid)
{
struct device *dev = to_device_index(csid, csid->id);
struct device *dev = csid->camss->dev;
u32 pixel_clock;
int i, j;
int ret;
......@@ -232,7 +232,9 @@ static int csid_set_clock_rates(struct csid_device *csid)
struct camss_clock *clock = &csid->clock[i];
if (!strcmp(clock->name, "csi0") ||
!strcmp(clock->name, "csi1")) {
!strcmp(clock->name, "csi1") ||
!strcmp(clock->name, "csi2") ||
!strcmp(clock->name, "csi3")) {
u8 bpp = csid_get_fmt_entry(
csid->fmt[MSM_CSIPHY_PAD_SINK].code)->bpp;
u8 num_lanes = csid->phy.lane_cnt;
......@@ -291,8 +293,7 @@ static int csid_reset(struct csid_device *csid)
time = wait_for_completion_timeout(&csid->reset_complete,
msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
if (!time) {
dev_err(to_device_index(csid, csid->id),
"CSID reset timeout\n");
dev_err(csid->camss->dev, "CSID reset timeout\n");
return -EIO;
}
......@@ -309,7 +310,7 @@ static int csid_reset(struct csid_device *csid)
static int csid_set_power(struct v4l2_subdev *sd, int on)
{
struct csid_device *csid = v4l2_get_subdevdata(sd);
struct device *dev = to_device_index(csid, csid->id);
struct device *dev = csid->camss->dev;
int ret;
if (on) {
......@@ -375,7 +376,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
ret = v4l2_ctrl_handler_setup(&csid->ctrls);
if (ret < 0) {
dev_err(to_device_index(csid, csid->id),
dev_err(csid->camss->dev,
"could not sync v4l2 controls: %d\n", ret);
return ret;
}
......@@ -796,15 +797,16 @@ static const struct v4l2_ctrl_ops csid_ctrl_ops = {
*
* Return 0 on success or a negative error code otherwise
*/
int msm_csid_subdev_init(struct csid_device *csid,
int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
const struct resources *res, u8 id)
{
struct device *dev = to_device_index(csid, id);
struct device *dev = camss->dev;
struct platform_device *pdev = to_platform_device(dev);
struct resource *r;
int i, j;
int ret;
csid->camss = camss;
csid->id = id;
/* Memory */
......@@ -1018,7 +1020,7 @@ int msm_csid_register_entity(struct csid_device *csid,
{
struct v4l2_subdev *sd = &csid->subdev;
struct media_pad *pads = csid->pads;
struct device *dev = to_device_index(csid, csid->id);
struct device *dev = csid->camss->dev;
int ret;
v4l2_subdev_init(sd, &csid_v4l2_ops);
......
......@@ -42,6 +42,7 @@ struct csid_phy_config {
};
struct csid_device {
struct camss *camss;
u8 id;
struct v4l2_subdev subdev;
struct media_pad pads[MSM_CSID_PADS_NUM];
......@@ -61,7 +62,7 @@ struct csid_device {
struct resources;
int msm_csid_subdev_init(struct csid_device *csid,
int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
const struct resources *res, u8 id);
int msm_csid_register_entity(struct csid_device *csid,
......
......@@ -155,7 +155,7 @@ static irqreturn_t csiphy_isr(int irq, void *dev)
*/
static int csiphy_set_clock_rates(struct csiphy_device *csiphy)
{
struct device *dev = to_device_index(csiphy, csiphy->id);
struct device *dev = csiphy->camss->dev;
u32 pixel_clock;
int i, j;
int ret;
......@@ -168,7 +168,8 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy)
struct camss_clock *clock = &csiphy->clock[i];
if (!strcmp(clock->name, "csiphy0_timer") ||
!strcmp(clock->name, "csiphy1_timer")) {
!strcmp(clock->name, "csiphy1_timer") ||
!strcmp(clock->name, "csiphy2_timer")) {
u8 bpp = csiphy_get_bpp(
csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
......@@ -233,7 +234,7 @@ static void csiphy_reset(struct csiphy_device *csiphy)
static int csiphy_set_power(struct v4l2_subdev *sd, int on)
{
struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
struct device *dev = to_device_index(csiphy, csiphy->id);
struct device *dev = csiphy->camss->dev;
if (on) {
u8 hw_version;
......@@ -311,12 +312,12 @@ static u8 csiphy_settle_cnt_calc(struct csiphy_device *csiphy)
ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock);
if (ret) {
dev_err(to_device_index(csiphy, csiphy->id),
dev_err(csiphy->camss->dev,
"Cannot get CSI2 transmitter's pixel clock\n");
return 0;
}
if (!pixel_clock) {
dev_err(to_device_index(csiphy, csiphy->id),
dev_err(csiphy->camss->dev,
"Got pixel clock == 0, cannot continue\n");
return 0;
}
......@@ -670,15 +671,17 @@ static int csiphy_init_formats(struct v4l2_subdev *sd,
*
* Return 0 on success or a negative error code otherwise
*/
int msm_csiphy_subdev_init(struct csiphy_device *csiphy,
int msm_csiphy_subdev_init(struct camss *camss,
struct csiphy_device *csiphy,
const struct resources *res, u8 id)
{
struct device *dev = to_device_index(csiphy, id);
struct device *dev = camss->dev;
struct platform_device *pdev = to_platform_device(dev);
struct resource *r;
int i, j;
int ret;
csiphy->camss = camss;
csiphy->id = id;
csiphy->cfg.combo_mode = 0;
......@@ -839,7 +842,7 @@ int msm_csiphy_register_entity(struct csiphy_device *csiphy,
{
struct v4l2_subdev *sd = &csiphy->subdev;
struct media_pad *pads = csiphy->pads;
struct device *dev = to_device_index(csiphy, csiphy->id);
struct device *dev = csiphy->camss->dev;
int ret;
v4l2_subdev_init(sd, &csiphy_v4l2_ops);
......
......@@ -42,6 +42,7 @@ struct csiphy_config {
};
struct csiphy_device {
struct camss *camss;
u8 id;
struct v4l2_subdev subdev;
struct media_pad pads[MSM_CSIPHY_PADS_NUM];
......@@ -58,7 +59,8 @@ struct csiphy_device {
struct resources;
int msm_csiphy_subdev_init(struct csiphy_device *csiphy,
int msm_csiphy_subdev_init(struct camss *camss,
struct csiphy_device *csiphy,
const struct resources *res, u8 id);
int msm_csiphy_register_entity(struct csiphy_device *csiphy,
......
......@@ -23,12 +23,6 @@
#define MSM_ISPIF_NAME "msm_ispif"
#define ispif_line_array(ptr_line) \
((const struct ispif_line (*)[]) &(ptr_line[-(ptr_line->id)]))
#define to_ispif(ptr_line) \
container_of(ispif_line_array(ptr_line), struct ispif_device, ptr_line)
#define ISPIF_RST_CMD_0 0x008
#define ISPIF_RST_CMD_0_STROBED_RST_EN (1 << 0)
#define ISPIF_RST_CMD_0_MISC_LOGIC_RST (1 << 1)
......@@ -225,7 +219,7 @@ static int ispif_reset(struct ispif_device *ispif)
static int ispif_set_power(struct v4l2_subdev *sd, int on)
{
struct ispif_line *line = v4l2_get_subdevdata(sd);
struct ispif_device *ispif = to_ispif(line);
struct ispif_device *ispif = line->ispif;
struct device *dev = to_device(ispif);
int ret = 0;
......@@ -611,7 +605,7 @@ static void ispif_set_intf_cmd(struct ispif_device *ispif, u8 cmd,
static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
{
struct ispif_line *line = v4l2_get_subdevdata(sd);
struct ispif_device *ispif = to_ispif(line);
struct ispif_device *ispif = line->ispif;
enum ispif_intf intf = line->interface;
u8 csid = line->csid_id;
u8 vfe = line->vfe_id;
......@@ -899,6 +893,24 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
int i;
int ret;
/* Number of ISPIF lines - same as number of CSID hardware modules */
if (to_camss(ispif)->version == CAMSS_8x16)
ispif->line_num = 2;
else if (to_camss(ispif)->version == CAMSS_8x96)
ispif->line_num = 4;
else
return -EINVAL;
ispif->line = kcalloc(ispif->line_num, sizeof(*ispif->line),
GFP_KERNEL);
if (!ispif->line)
return -ENOMEM;
for (i = 0; i < ispif->line_num; i++) {
ispif->line[i].ispif = ispif;
ispif->line[i].id = i;
}
/* Memory */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
......@@ -979,9 +991,6 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
clock->nfreqs = 0;
}
for (i = 0; i < ARRAY_SIZE(ispif->line); i++)
ispif->line[i].id = i;
mutex_init(&ispif->power_lock);
ispif->power_count = 0;
......@@ -1100,7 +1109,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
int ret;
int i;
for (i = 0; i < ARRAY_SIZE(ispif->line); i++) {
for (i = 0; i < ispif->line_num; i++) {
struct v4l2_subdev *sd = &ispif->line[i].subdev;
struct media_pad *pads = ispif->line[i].pads;
......@@ -1161,7 +1170,7 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
mutex_destroy(&ispif->power_lock);
mutex_destroy(&ispif->config_lock);
for (i = 0; i < ARRAY_SIZE(ispif->line); i++) {
for (i = 0; i < ispif->line_num; i++) {
struct v4l2_subdev *sd = &ispif->line[i].subdev;
v4l2_device_unregister_subdev(sd);
......
......@@ -15,14 +15,11 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
/* Number of ISPIF lines - same as number of CSID hardware modules */
#define MSM_ISPIF_LINE_NUM 2
#define MSM_ISPIF_PAD_SINK 0
#define MSM_ISPIF_PAD_SRC 1
#define MSM_ISPIF_PADS_NUM 2
#define MSM_ISPIF_VFE_NUM 1
#define MSM_ISPIF_VFE_NUM 2
enum ispif_intf {
PIX0,
......@@ -38,6 +35,7 @@ struct ispif_intf_cmd_reg {
};
struct ispif_line {
struct ispif_device *ispif;
u8 id;
u8 csid_id;
u8 vfe_id;
......@@ -61,7 +59,8 @@ struct ispif_device {
struct mutex power_lock;
struct ispif_intf_cmd_reg intf_cmd[MSM_ISPIF_VFE_NUM];
struct mutex config_lock;
struct ispif_line line[MSM_ISPIF_LINE_NUM];
unsigned int line_num;
struct ispif_line *line;
};
struct resources_ispif;
......
......@@ -877,7 +877,7 @@ static int vfe_reset(struct vfe_device *vfe)
time = wait_for_completion_timeout(&vfe->reset_complete,
msecs_to_jiffies(VFE_RESET_TIMEOUT_MS));
if (!time) {
dev_err(to_device(vfe), "VFE reset timeout\n");
dev_err(vfe->camss->dev, "VFE reset timeout\n");
return -EIO;
}
......@@ -902,7 +902,7 @@ static int vfe_halt(struct vfe_device *vfe)
time = wait_for_completion_timeout(&vfe->halt_complete,
msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
if (!time) {
dev_err(to_device(vfe), "VFE halt timeout\n");
dev_err(vfe->camss->dev, "VFE halt timeout\n");
return -EIO;
}
......@@ -1041,7 +1041,7 @@ static int vfe_camif_wait_for_stop(struct vfe_device *vfe)
CAMIF_TIMEOUT_SLEEP_US,
CAMIF_TIMEOUT_ALL_US);
if (ret < 0)
dev_err(to_device(vfe), "%s: camif stop timeout\n", __func__);
dev_err(vfe->camss->dev, "%s: camif stop timeout\n", __func__);
return ret;
}
......@@ -1209,7 +1209,7 @@ static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
break;
case VFE_OUTPUT_SINGLE:
default:
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"Next buf in wrong state! %d\n",
output->state);
break;
......@@ -1229,7 +1229,7 @@ static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
vfe_output_frame_drop(vfe, output, 0);
break;
default:
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"Last buff in wrong state! %d\n",
output->state);
break;
......@@ -1258,7 +1258,7 @@ static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
output->state = VFE_OUTPUT_CONTINUOUS;
} else {
vfe_buf_add_pending(output, new_buf);
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"Inactive buffer is busy\n");
}
break;
......@@ -1273,7 +1273,7 @@ static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
output->state = VFE_OUTPUT_SINGLE;
} else {
vfe_buf_add_pending(output, new_buf);
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"Output idle with buffer set!\n");
}
break;
......@@ -1297,7 +1297,7 @@ static int vfe_get_output(struct vfe_line *line)
output = &line->output;
if (output->state != VFE_OUTPUT_OFF) {
dev_err(to_device(vfe), "Output is running\n");
dev_err(vfe->camss->dev, "Output is running\n");
goto error;
}
output->state = VFE_OUTPUT_RESERVED;
......@@ -1307,7 +1307,7 @@ static int vfe_get_output(struct vfe_line *line)
for (i = 0; i < output->wm_num; i++) {
wm_idx = vfe_reserve_wm(vfe, line->id);
if (wm_idx < 0) {
dev_err(to_device(vfe), "Can not reserve wm\n");
dev_err(vfe->camss->dev, "Can not reserve wm\n");
goto error_get_wm;
}
output->wm_idx[i] = wm_idx;
......@@ -1371,7 +1371,7 @@ static int vfe_enable_output(struct vfe_line *line)
vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line->id);
if (output->state != VFE_OUTPUT_RESERVED) {
dev_err(to_device(vfe), "Output is not in reserved state %d\n",
dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
output->state);
spin_unlock_irqrestore(&vfe->output_lock, flags);
return -EINVAL;
......@@ -1471,7 +1471,7 @@ static int vfe_disable_output(struct vfe_line *line)
time = wait_for_completion_timeout(&output->sof,
msecs_to_jiffies(VFE_NEXT_SOF_MS));
if (!time)
dev_err(to_device(vfe), "VFE sof timeout\n");
dev_err(vfe->camss->dev, "VFE sof timeout\n");
spin_lock_irqsave(&vfe->output_lock, flags);
for (i = 0; i < output->wm_num; i++)
......@@ -1484,7 +1484,7 @@ static int vfe_disable_output(struct vfe_line *line)
time = wait_for_completion_timeout(&output->reg_update,
msecs_to_jiffies(VFE_NEXT_SOF_MS));
if (!time)
dev_err(to_device(vfe), "VFE reg update timeout\n");
dev_err(vfe->camss->dev, "VFE reg update timeout\n");
spin_lock_irqsave(&vfe->output_lock, flags);
......@@ -1698,14 +1698,14 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
spin_lock_irqsave(&vfe->output_lock, flags);
if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"Received wm done for unmapped index\n");
goto out_unlock;
}
output = &vfe->line[vfe->wm_output_map[wm]].output;
if (output->active_buf == active_index) {
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"Active buffer mismatch!\n");
goto out_unlock;
}
......@@ -1713,7 +1713,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
ready_buf = output->buf[!active_index];
if (!ready_buf) {
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"Missing ready buf %d %d!\n",
!active_index, output->state);
goto out_unlock;
......@@ -1799,7 +1799,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION) {
violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
dev_err_ratelimited(to_device(vfe),
dev_err_ratelimited(vfe->camss->dev,
"VFE: violation = 0x%08x\n", violation);
}
......@@ -1842,7 +1842,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
*/
static int vfe_set_clock_rates(struct vfe_device *vfe)
{
struct device *dev = to_device(vfe);
struct device *dev = vfe->camss->dev;
u32 pixel_clock[MSM_VFE_LINE_NUM];
int i, j;
int ret;
......@@ -1857,7 +1857,8 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
for (i = 0; i < vfe->nclocks; i++) {
struct camss_clock *clock = &vfe->clock[i];
if (!strcmp(clock->name, "camss_vfe_vfe")) {
if (!strcmp(clock->name, "vfe0") ||
!strcmp(clock->name, "vfe1")) {
u64 min_rate = 0;
long rate;
......@@ -1935,7 +1936,8 @@ static int vfe_check_clock_rates(struct vfe_device *vfe)
for (i = 0; i < vfe->nclocks; i++) {
struct camss_clock *clock = &vfe->clock[i];
if (!strcmp(clock->name, "camss_vfe_vfe")) {
if (!strcmp(clock->name, "vfe0") ||
!strcmp(clock->name, "vfe1")) {
u64 min_rate = 0;
unsigned long rate;
......@@ -1984,7 +1986,7 @@ static int vfe_get(struct vfe_device *vfe)
goto error_clocks;
ret = camss_enable_clocks(vfe->nclocks, vfe->clock,
to_device(vfe));
vfe->camss->dev);
if (ret < 0)
goto error_clocks;
......@@ -2024,7 +2026,7 @@ static void vfe_put(struct vfe_device *vfe)
mutex_lock(&vfe->power_lock);
if (vfe->power_count == 0) {
dev_err(to_device(vfe), "vfe power off on power_count == 0\n");
dev_err(vfe->camss->dev, "vfe power off on power_count == 0\n");
goto exit;
} else if (vfe->power_count == 1) {
if (vfe->was_streaming) {
......@@ -2130,7 +2132,7 @@ static int vfe_set_power(struct v4l2_subdev *sd, int on)
return ret;
hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION);
dev_dbg(to_device(vfe),
dev_dbg(vfe->camss->dev,
"VFE HW Version = 0x%08x\n", hw_version);
} else {
vfe_put(vfe);
......@@ -2157,12 +2159,12 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
if (enable) {
ret = vfe_enable(line);
if (ret < 0)
dev_err(to_device(vfe),
dev_err(vfe->camss->dev,
"Failed to enable vfe outputs\n");
} else {
ret = vfe_disable(line);
if (ret < 0)
dev_err(to_device(vfe),
dev_err(vfe->camss->dev,
"Failed to disable vfe outputs\n");
}
......@@ -2716,12 +2718,12 @@ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
*
* Return 0 on success or a negative error code otherwise
*/
int msm_vfe_subdev_init(struct vfe_device *vfe, const struct resources *res)
int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
const struct resources *res, u8 id)
{
struct device *dev = to_device(vfe);
struct device *dev = camss->dev;
struct platform_device *pdev = to_platform_device(dev);
struct resource *r;
struct camss *camss = to_camss(vfe);
int i, j;
int ret;
......@@ -2801,7 +2803,8 @@ int msm_vfe_subdev_init(struct vfe_device *vfe, const struct resources *res)
spin_lock_init(&vfe->output_lock);
vfe->id = 0;
vfe->camss = camss;
vfe->id = id;
vfe->reg_update = 0;
for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) {
......@@ -2933,7 +2936,7 @@ void msm_vfe_stop_streaming(struct vfe_device *vfe)
int msm_vfe_register_entities(struct vfe_device *vfe,
struct v4l2_device *v4l2_dev)
{
struct device *dev = to_device(vfe);
struct device *dev = vfe->camss->dev;
struct v4l2_subdev *sd;
struct media_pad *pads;
struct camss_video *video_out;
......
......@@ -79,6 +79,7 @@ struct vfe_line {
};
struct vfe_device {
struct camss *camss;
u8 id;
void __iomem *base;
u32 irq;
......@@ -100,7 +101,8 @@ struct vfe_device {
struct resources;
int msm_vfe_subdev_init(struct vfe_device *vfe, const struct resources *res);
int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
const struct resources *res, u8 id);
int msm_vfe_register_entities(struct vfe_device *vfe,
struct v4l2_device *v4l2_dev);
......
This diff is collapsed.
......@@ -23,9 +23,6 @@
#include "camss-ispif.h"
#include "camss-vfe.h"
#define CAMSS_CSID_NUM 2
#define CAMSS_CSIPHY_NUM 2
#define to_camss(ptr_module) \
container_of(ptr_module, struct camss, ptr_module)
......@@ -42,7 +39,7 @@
#define to_device_index(ptr_module, index) \
(to_camss_index(ptr_module, index)->dev)
#define CAMSS_RES_MAX 15
#define CAMSS_RES_MAX 17
struct resources {
char *regulator[CAMSS_RES_MAX];
......@@ -59,15 +56,24 @@ struct resources_ispif {
char *interrupt;
};
enum camss_version {
CAMSS_8x16,
CAMSS_8x96,
};
struct camss {
enum camss_version version;
struct v4l2_device v4l2_dev;
struct v4l2_async_notifier notifier;
struct media_device media_dev;
struct device *dev;
struct csiphy_device csiphy[CAMSS_CSIPHY_NUM];
struct csid_device csid[CAMSS_CSID_NUM];
int csiphy_num;
struct csiphy_device *csiphy;
int csid_num;
struct csid_device *csid;
struct ispif_device ispif;
struct vfe_device vfe;
int vfe_num;
struct vfe_device *vfe;
atomic_t ref_count;
};
......
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