[RFC 11/21] DRM: Add VIA DRM driver
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
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; +