[RFC 11/21] DRM: Add VIA DRM driver

2013-06-08 Thread James Simmons

commit 4ed0199a92b71506100240b625da173ef7afaf4c
Author: James Simmons 
Date:   Sat Jun 8 10:57:59 2013 -0400

via: VIA clock handling

The routines that generate the PLL values to program the registers with.
Here the VCLK is programmed to properly set the video mode.

Signed-Off-by: James Simmons 

diff --git a/drivers/gpu/drm/via/via_clocks.c b/drivers/gpu/drm/via/via_clocks.c
new file mode 100644
index 000..eae424a
--- /dev/null
+++ b/drivers/gpu/drm/via/via_clocks.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2012 James Simmons 
+ *
+ * Based on code for the viafb driver.
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+ */
+
+#include "drmP.h"
+#include "via_drv.h"
+
+#define CSR_VCO_UP 6
+#define CSR_VCO_DOWN   3
+
+#define PLL_DTZ_DEFAULT(BIT(0) | BIT(1))
+
+#define VIA_CLK_REFERENCE  14318180
+
+struct pll_mrn_value {
+   u32 pll_m;
+   u32 pll_r;
+   u32 pll_n;
+   u32 diff_clk;
+   u32 pll_fout;
+};
+
+/*
+ * This function first gets the best frequency M, R, N value
+ * to program the PLL according to the supplied frequence
+ * passed in. After we get the MRN values the results are
+ * formatted to fit properly into the PLL clock registers.
+ *
+ * PLL registers M, R, N value
+ * [31:16]  DM[7:0]
+ * [15:8 ]  DR[2:0]
+ * [7 :0 ]  DN[6:0]
+ */
+u32
+via_get_clk_value(struct drm_device *dev, u32 freq)
+{
+   u32 best_pll_n = 2, best_pll_r = 0, best_pll_m = 2, best_clk_diff = 
freq;
+   u32 pll_fout, pll_fvco, pll_mrn = 0;
+   u32 pll_n, pll_r, pll_m, clk_diff;
+   struct pll_mrn_value pll_tmp[5] = {
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 } };
+   int count;
+
+   /* DN[6:0] */
+   for (pll_n = 2; pll_n < 6; pll_n++) {
+   /* DR[2:0] */
+   for (pll_r = 0; pll_r < 6; pll_r++) {
+   /* DM[9:0] */
+   for (pll_m = 2; pll_m < 512; pll_m++) {
+   /* first divide pll_n then multiply
+* pll_m. We have to reduce pll_m
+* to 512 to get rid of the overflow */
+   pll_fvco = (VIA_CLK_REFERENCE / pll_n) * pll_m;
+   if ((pll_fvco >= CSR_VCO_DOWN) && (pll_fvco <= 
CSR_VCO_UP)) {
+   pll_fout = pll_fvco >> pll_r;
+   if (pll_fout < freq)
+   clk_diff = freq - pll_fout;
+   else
+   clk_diff = pll_fout - freq;
+
+   /* if frequency (which is the PLL we 
want
+* to set) > 150MHz, the MRN value we
+* write in register must < frequency, 
and
+* get MRN value whose M is the 
largeset */
+   if (freq >= 15000) {
+   if ((clk_diff <= 
pll_tmp[0].diff_clk) || pll_tmp[0].pll_fout == 0) {
+   for (count = 
ARRAY_SIZE(pll_tmp) - 1; count >= 1; count--)
+   pll_tmp[count] 
= pll_tmp[count - 1];
+
+   pll_tmp[0].pll_m = 
pll_m;
+   pll_tmp[0].pll_r = 
pll_r;
+   pll_tmp[0].pll_n = 
pll_n;
+   pll_tmp[0].diff_clk = 
clk_diff;
+   pll_tmp[0].pll_fout = 
pll_fout;
+   }
+   }
+
+   if (clk_diff < best_clk_diff) {
+   best_clk_diff = clk_diff;
+   best_pll_m = pll_m;
+   best_pll_n = pll_n;
+   best_pll_r = pll_r;
+ 

[RFC 11/21] DRM: Add VIA DRM driver

2013-06-08 Thread James Simmons

commit 4ed0199a92b71506100240b625da173ef7afaf4c
Author: James Simmons jsimm...@infradead.org
Date:   Sat Jun 8 10:57:59 2013 -0400

via: VIA clock handling

The routines that generate the PLL values to program the registers with.
Here the VCLK is programmed to properly set the video mode.

Signed-Off-by: James Simmons jsimm...@infradead.org

diff --git a/drivers/gpu/drm/via/via_clocks.c b/drivers/gpu/drm/via/via_clocks.c
new file mode 100644
index 000..eae424a
--- /dev/null
+++ b/drivers/gpu/drm/via/via_clocks.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2012 James Simmons jsimm...@infradead.org
+ *
+ * Based on code for the viafb driver.
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+ */
+
+#include drmP.h
+#include via_drv.h
+
+#define CSR_VCO_UP 6
+#define CSR_VCO_DOWN   3
+
+#define PLL_DTZ_DEFAULT(BIT(0) | BIT(1))
+
+#define VIA_CLK_REFERENCE  14318180
+
+struct pll_mrn_value {
+   u32 pll_m;
+   u32 pll_r;
+   u32 pll_n;
+   u32 diff_clk;
+   u32 pll_fout;
+};
+
+/*
+ * This function first gets the best frequency M, R, N value
+ * to program the PLL according to the supplied frequence
+ * passed in. After we get the MRN values the results are
+ * formatted to fit properly into the PLL clock registers.
+ *
+ * PLL registers M, R, N value
+ * [31:16]  DM[7:0]
+ * [15:8 ]  DR[2:0]
+ * [7 :0 ]  DN[6:0]
+ */
+u32
+via_get_clk_value(struct drm_device *dev, u32 freq)
+{
+   u32 best_pll_n = 2, best_pll_r = 0, best_pll_m = 2, best_clk_diff = 
freq;
+   u32 pll_fout, pll_fvco, pll_mrn = 0;
+   u32 pll_n, pll_r, pll_m, clk_diff;
+   struct pll_mrn_value pll_tmp[5] = {
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 },
+   { 0, 0, 0, 0, 0 } };
+   int count;
+
+   /* DN[6:0] */
+   for (pll_n = 2; pll_n  6; pll_n++) {
+   /* DR[2:0] */
+   for (pll_r = 0; pll_r  6; pll_r++) {
+   /* DM[9:0] */
+   for (pll_m = 2; pll_m  512; pll_m++) {
+   /* first divide pll_n then multiply
+* pll_m. We have to reduce pll_m
+* to 512 to get rid of the overflow */
+   pll_fvco = (VIA_CLK_REFERENCE / pll_n) * pll_m;
+   if ((pll_fvco = CSR_VCO_DOWN)  (pll_fvco = 
CSR_VCO_UP)) {
+   pll_fout = pll_fvco  pll_r;
+   if (pll_fout  freq)
+   clk_diff = freq - pll_fout;
+   else
+   clk_diff = pll_fout - freq;
+
+   /* if frequency (which is the PLL we 
want
+* to set)  150MHz, the MRN value we
+* write in register must  frequency, 
and
+* get MRN value whose M is the 
largeset */
+   if (freq = 15000) {
+   if ((clk_diff = 
pll_tmp[0].diff_clk) || pll_tmp[0].pll_fout == 0) {
+   for (count = 
ARRAY_SIZE(pll_tmp) - 1; count = 1; count--)
+   pll_tmp[count] 
= pll_tmp[count - 1];
+
+   pll_tmp[0].pll_m = 
pll_m;
+   pll_tmp[0].pll_r = 
pll_r;
+   pll_tmp[0].pll_n = 
pll_n;
+   pll_tmp[0].diff_clk = 
clk_diff;
+   pll_tmp[0].pll_fout = 
pll_fout;
+   }
+   }
+
+   if (clk_diff  best_clk_diff) {
+   best_clk_diff = clk_diff;
+   best_pll_m = pll_m;
+   best_pll_n = pll_n;
+