struct tegra_dpaux *dpaux;
+ struct mutex lock;
bool enabled;
struct dentry *debugfs;
unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
struct tegra_sor *sor = to_sor(output);
unsigned long value;
- int err;
+ int err = 0;
+
+ mutex_lock(&sor->lock);
if (sor->enabled)
- return 0;
+ goto unlock;
err = clk_prepare_enable(sor->clk);
if (err < 0)
- return err;
+ goto unlock;
reset_control_deassert(sor->rst);
err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS);
if (err < 0) {
dev_err(sor->dev, "failed to power on I/O rail: %d\n", err);
- return err;
+ goto unlock;
}
usleep_range(5, 100);
if (err < 0) {
dev_err(sor->dev, "failed to probe eDP link: %d\n",
err);
- return err;
+ goto unlock;
}
err = drm_dp_link_power_up(aux, &link);
if (err < 0) {
dev_err(sor->dev, "failed to power up eDP link: %d\n",
err);
- return err;
+ goto unlock;
}
err = drm_dp_link_configure(aux, &link);
if (err < 0) {
dev_err(sor->dev, "failed to configure eDP link: %d\n",
err);
- return err;
+ goto unlock;
}
rate = drm_dp_link_rate_to_bw_code(link.rate);
if (err < 0) {
dev_err(sor->dev, "DP fast link training failed: %d\n",
err);
- return err;
+ goto unlock;
}
dev_dbg(sor->dev, "fast link training succeeded\n");
err = tegra_sor_power_up(sor, 250);
if (err < 0) {
dev_err(sor->dev, "failed to power up SOR: %d\n", err);
- return err;
+ goto unlock;
}
/* start display controller in continuous mode */
err = tegra_sor_setup_pwm(sor, 250);
if (err < 0) {
dev_err(sor->dev, "failed to setup PWM: %d\n", err);
- return err;
+ goto unlock;
}
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
err = tegra_sor_attach(sor);
if (err < 0) {
dev_err(sor->dev, "failed to attach SOR: %d\n", err);
- return err;
+ goto unlock;
}
err = tegra_sor_wakeup(sor);
if (err < 0) {
dev_err(sor->dev, "failed to enable DC: %d\n", err);
- return err;
+ goto unlock;
}
sor->enabled = true;
- return 0;
+unlock:
+ mutex_unlock(&sor->lock);
+ return err;
}
static int tegra_sor_detach(struct tegra_sor *sor)
struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
struct tegra_sor *sor = to_sor(output);
unsigned long value;
- int err;
+ int err = 0;
+
+ mutex_lock(&sor->lock);
if (!sor->enabled)
- return 0;
+ goto unlock;
err = tegra_sor_detach(sor);
if (err < 0) {
dev_err(sor->dev, "failed to detach SOR: %d\n", err);
- return err;
+ goto unlock;
}
tegra_sor_writel(sor, 0, SOR_STATE_1);
err = tegra_sor_power_down(sor);
if (err < 0) {
dev_err(sor->dev, "failed to power down SOR: %d\n", err);
- return err;
+ goto unlock;
}
if (sor->dpaux) {
err = tegra_dpaux_disable(sor->dpaux);
if (err < 0) {
dev_err(sor->dev, "failed to disable DP: %d\n", err);
- return err;
+ goto unlock;
}
}
err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS);
if (err < 0) {
dev_err(sor->dev, "failed to power off I/O rail: %d\n", err);
- return err;
+ goto unlock;
}
reset_control_assert(sor->rst);
sor->enabled = false;
- return 0;
+unlock:
+ mutex_unlock(&sor->lock);
+ return err;
}
static int tegra_output_sor_setup_clock(struct tegra_output *output,
size_t size, loff_t *ppos)
{
struct tegra_sor *sor = file->private_data;
+ ssize_t num, err;
char buf[10];
- ssize_t num;
u32 value;
- int err;
+
+ mutex_lock(&sor->lock);
+
+ if (!sor->enabled) {
+ err = -EAGAIN;
+ goto unlock;
+ }
value = tegra_sor_readl(sor, SOR_STATE_1);
value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
err = tegra_sor_crc_wait(sor, 100);
if (err < 0)
- return err;
+ goto unlock;
tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
value = tegra_sor_readl(sor, SOR_CRC_B);
num = scnprintf(buf, sizeof(buf), "%08x\n", value);
- return simple_read_from_buffer(buffer, size, ppos, buf, num);
+ err = simple_read_from_buffer(buffer, size, ppos, buf, num);
+
+unlock:
+ mutex_unlock(&sor->lock);
+ return err;
}
static const struct file_operations tegra_sor_crc_fops = {
sor->client.ops = &sor_client_ops;
sor->client.dev = &pdev->dev;
+ mutex_init(&sor->lock);
+
err = host1x_client_register(&sor->client);
if (err < 0) {
dev_err(&pdev->dev, "failed to register host1x client: %d\n",