|
@@ -12,6 +12,7 @@
|
|
|
* in an attempt to provide to the rest of the driver code a unified view
|
|
|
*/
|
|
|
|
|
|
+#include <linux/clk.h>
|
|
|
#include <linux/types.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <drm/drmP.h>
|
|
@@ -334,6 +335,39 @@ static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
|
|
|
+ struct malidp_se_config *se_config,
|
|
|
+ struct videomode *vm)
|
|
|
+{
|
|
|
+ unsigned long mclk;
|
|
|
+ unsigned long pxlclk = vm->pixelclock; /* Hz */
|
|
|
+ unsigned long htotal = vm->hactive + vm->hfront_porch +
|
|
|
+ vm->hback_porch + vm->hsync_len;
|
|
|
+ unsigned long input_size = se_config->input_w * se_config->input_h;
|
|
|
+ unsigned long a = 10;
|
|
|
+ long ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * mclk = max(a, 1.5) * pxlclk
|
|
|
+ *
|
|
|
+ * To avoid float calculaiton, using 15 instead of 1.5 and div by
|
|
|
+ * 10 to get mclk.
|
|
|
+ */
|
|
|
+ if (se_config->scale_enable) {
|
|
|
+ a = 15 * input_size / (htotal * se_config->output_h);
|
|
|
+ if (a < 15)
|
|
|
+ a = 15;
|
|
|
+ }
|
|
|
+ mclk = a * pxlclk / 10;
|
|
|
+ ret = clk_get_rate(hwdev->mclk);
|
|
|
+ if (ret < mclk) {
|
|
|
+ DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
|
|
|
+ mclk / 1000);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int malidp550_query_hw(struct malidp_hw_device *hwdev)
|
|
|
{
|
|
|
u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
|
|
@@ -521,6 +555,39 @@ static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
|
|
|
+ struct malidp_se_config *se_config,
|
|
|
+ struct videomode *vm)
|
|
|
+{
|
|
|
+ unsigned long mclk;
|
|
|
+ unsigned long pxlclk = vm->pixelclock;
|
|
|
+ unsigned long htotal = vm->hactive + vm->hfront_porch +
|
|
|
+ vm->hback_porch + vm->hsync_len;
|
|
|
+ unsigned long numerator = 1, denominator = 1;
|
|
|
+ long ret;
|
|
|
+
|
|
|
+ if (se_config->scale_enable) {
|
|
|
+ numerator = max(se_config->input_w, se_config->output_w) *
|
|
|
+ se_config->input_h;
|
|
|
+ numerator += se_config->output_w *
|
|
|
+ (se_config->output_h -
|
|
|
+ min(se_config->input_h, se_config->output_h));
|
|
|
+ denominator = (htotal - 2) * se_config->output_h;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* mclk can't be slower than pxlclk. */
|
|
|
+ if (numerator < denominator)
|
|
|
+ numerator = denominator = 1;
|
|
|
+ mclk = (pxlclk * numerator) / denominator;
|
|
|
+ ret = clk_get_rate(hwdev->mclk);
|
|
|
+ if (ret < mclk) {
|
|
|
+ DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
|
|
|
+ mclk / 1000);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int malidp650_query_hw(struct malidp_hw_device *hwdev)
|
|
|
{
|
|
|
u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
|
|
@@ -586,6 +653,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
|
|
|
.modeset = malidp500_modeset,
|
|
|
.rotmem_required = malidp500_rotmem_required,
|
|
|
.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
|
|
|
+ .se_calc_mclk = malidp500_se_calc_mclk,
|
|
|
.features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
|
|
|
},
|
|
|
[MALIDP_550] = {
|
|
@@ -622,6 +690,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
|
|
|
.modeset = malidp550_modeset,
|
|
|
.rotmem_required = malidp550_rotmem_required,
|
|
|
.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
|
|
|
+ .se_calc_mclk = malidp550_se_calc_mclk,
|
|
|
.features = 0,
|
|
|
},
|
|
|
[MALIDP_650] = {
|
|
@@ -659,6 +728,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
|
|
|
.modeset = malidp550_modeset,
|
|
|
.rotmem_required = malidp550_rotmem_required,
|
|
|
.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
|
|
|
+ .se_calc_mclk = malidp550_se_calc_mclk,
|
|
|
.features = 0,
|
|
|
},
|
|
|
};
|