/*
 * Copyright (C) 2015 Texas Instruments
 * Author: Jyri Sarha <jsarha@ti.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 */

#include <linux/component.h>
#include <linux/of_graph.h>

#include "tilcdc_drv.h"
#include "tilcdc_external.h"

static const struct tilcdc_panel_info panel_info_tda998x = {
		.ac_bias                = 255,
		.ac_bias_intrpt         = 0,
		.dma_burst_sz           = 16,
		.bpp                    = 16,
		.fdd                    = 0x80,
		.tft_alt_mode           = 0,
		.invert_pxl_clk		= 1,
		.sync_edge              = 1,
		.sync_ctrl              = 1,
		.raster_order           = 0,
};

static int tilcdc_external_mode_valid(struct drm_connector *connector,
				      struct drm_display_mode *mode)
{
	struct tilcdc_drm_private *priv = connector->dev->dev_private;
	int ret, i;

	ret = tilcdc_crtc_mode_valid(priv->crtc, mode);
	if (ret != MODE_OK)
		return ret;

	for (i = 0; i < priv->num_connectors &&
		     priv->connectors[i] != connector; i++)
		;

	BUG_ON(priv->connectors[i] != connector);
	BUG_ON(!priv->connector_funcs[i]);

	/* If the connector has its own mode_valid call it. */
	if (!IS_ERR(priv->connector_funcs[i]) &&
	    priv->connector_funcs[i]->mode_valid)
		return priv->connector_funcs[i]->mode_valid(connector, mode);

	return MODE_OK;
}

static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
				       struct drm_connector *connector)
{
	struct tilcdc_drm_private *priv = dev->dev_private;
	struct drm_connector_helper_funcs *connector_funcs;

	priv->connectors[priv->num_connectors] = connector;
	priv->encoders[priv->num_encoders++] = connector->encoder;

	/* Only tda998x is supported at the moment. */
	tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
	tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
	*bpp = panel_info_tda998x.bpp;

	connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs),
				       GFP_KERNEL);
	if (!connector_funcs)
		return -ENOMEM;

	/* connector->helper_private contains always struct
	 * connector_helper_funcs pointer. For tilcdc crtc to have a
	 * say if a specific mode is Ok, we need to install our own
	 * helper functions. In our helper functions we copy
	 * everything else but use our own mode_valid() (above).
	 */
	if (connector->helper_private) {
		priv->connector_funcs[priv->num_connectors] =
			connector->helper_private;
		*connector_funcs = *priv->connector_funcs[priv->num_connectors];
	} else {
		priv->connector_funcs[priv->num_connectors] = ERR_PTR(-ENOENT);
	}
	connector_funcs->mode_valid = tilcdc_external_mode_valid;
	drm_connector_helper_add(connector, connector_funcs);
	priv->num_connectors++;

	dev_dbg(dev->dev, "External encoder '%s' connected\n",
		connector->encoder->name);

	return 0;
}

int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp)
{
	struct tilcdc_drm_private *priv = dev->dev_private;
	struct drm_connector *connector;
	int num_internal_connectors = priv->num_connectors;

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		bool found = false;
		int i, ret;

		for (i = 0; i < num_internal_connectors; i++)
			if (connector == priv->connectors[i])
				found = true;
		if (!found) {
			ret = tilcdc_add_external_encoder(dev, bpp, connector);
			if (ret)
				return ret;
		}
	}
	return 0;
}

void tilcdc_remove_external_encoders(struct drm_device *dev)
{
	struct tilcdc_drm_private *priv = dev->dev_private;
	int i;

	/* Restore the original helper functions, if any. */
	for (i = 0; i < priv->num_connectors; i++)
		if (IS_ERR(priv->connector_funcs[i]))
			drm_connector_helper_add(priv->connectors[i], NULL);
		else if (priv->connector_funcs[i])
			drm_connector_helper_add(priv->connectors[i],
						 priv->connector_funcs[i]);
}

static int dev_match_of(struct device *dev, void *data)
{
	return dev->of_node == data;
}

int tilcdc_get_external_components(struct device *dev,
				   struct component_match **match)
{
	struct device_node *ep = NULL;
	int count = 0;

	while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) {
		struct device_node *node;

		node = of_graph_get_remote_port_parent(ep);
		if (!node && !of_device_is_available(node)) {
			of_node_put(node);
			continue;
		}

		dev_dbg(dev, "Subdevice node '%s' found\n", node->name);
		if (match)
			component_match_add(dev, match, dev_match_of, node);
		of_node_put(node);
		count++;
	}

	if (count > 1) {
		dev_err(dev, "Only one external encoder is supported\n");
		return -EINVAL;
	}

	return count;
}
