summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/rcar-du/rcar_du_crtc.c')
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c51
1 files changed, 46 insertions, 5 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 5685d5af6998..c4420538ec85 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -125,14 +125,55 @@ static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc,
unsigned int m;
unsigned int n;
- for (n = 39; n < 120; n++) {
- for (m = 0; m < 4; m++) {
+ /*
+ * fin fvco fout fclkout
+ * in --> [1/M] --> |PD| -> [LPF] -> [VCO] -> [1/P] -+-> [1/FDPLL] -> out
+ * +-> | | |
+ * | |
+ * +---------------- [1/N] <------------+
+ *
+ * fclkout = fvco / P / FDPLL -- (1)
+ *
+ * fin/M = fvco/P/N
+ *
+ * fvco = fin * P * N / M -- (2)
+ *
+ * (1) + (2) indicates
+ *
+ * fclkout = fin * N / M / FDPLL
+ *
+ * NOTES
+ * N : (n + 1)
+ * M : (m + 1)
+ * FDPLL : (fdpll + 1)
+ * P : 2
+ * 2kHz < fvco < 4096MHz
+ *
+ * To minimize the jitter,
+ * N : as large as possible
+ * M : as small as possible
+ */
+ for (m = 0; m < 4; m++) {
+ for (n = 119; n > 38; n--) {
+ /*
+ * This code only runs on 64-bit architectures, the
+ * unsigned long type can thus be used for 64-bit
+ * computation. It will still compile without any
+ * warning on 32-bit architectures.
+ *
+ * To optimize calculations, use fout instead of fvco
+ * to verify the VCO frequency constraint.
+ */
+ unsigned long fout = input * (n + 1) / (m + 1);
+
+ if (fout < 1000 || fout > 2048 * 1000 * 1000U)
+ continue;
+
for (fdpll = 1; fdpll < 32; fdpll++) {
unsigned long output;
- output = input * (n + 1) / (m + 1)
- / (fdpll + 1);
- if (output >= 400000000)
+ output = fout / (fdpll + 1);
+ if (output >= 400 * 1000 * 1000)
continue;
diff = abs((long)output - (long)target);