drivers/gpu/drm/gma500/oaktrail_crtc.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/gma500/oaktrail_crtc.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/gma500/oaktrail_crtc.c
Extension
.c
Size
18477 bytes
Lines
662
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

switch (dev_priv->core_freq) {
		case 100:
			limit = &mrst_limits[MRST_LIMIT_LVDS_100L];
			break;
		case 166:
			limit = &mrst_limits[MRST_LIMIT_LVDS_83];
			break;
		case 200:
			limit = &mrst_limits[MRST_LIMIT_LVDS_100];
			break;
		}
	} else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
		limit = &mrst_limits[MRST_LIMIT_SDVO];
	} else {
		limit = NULL;
		dev_err(dev->dev, "mrst_limit Wrong display type.\n");
	}

	return limit;
}

/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
static void mrst_lvds_clock(int refclk, struct gma_clock_t *clock)
{
	clock->dot = (refclk * clock->m) / (14 * clock->p1);
}

static void mrst_print_pll(struct gma_clock_t *clock)
{
	DRM_DEBUG_DRIVER("dotclock=%d,  m=%d, m1=%d, m2=%d, n=%d, p1=%d, p2=%d\n",
			 clock->dot, clock->m, clock->m1, clock->m2, clock->n,
			 clock->p1, clock->p2);
}

static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit,
				    struct drm_crtc *crtc, int target,
				    int refclk, struct gma_clock_t *best_clock)
{
	struct gma_clock_t clock;
	u32 target_vco, actual_freq;
	s32 freq_error, min_error = 100000;

	memset(best_clock, 0, sizeof(*best_clock));
	memset(&clock, 0, sizeof(clock));

	for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
		for (clock.n = limit->n.min; clock.n <= limit->n.max;
		     clock.n++) {
			for (clock.p1 = limit->p1.min;
			     clock.p1 <= limit->p1.max; clock.p1++) {
				/* p2 value always stored in p2_slow on SDVO */
				clock.p = clock.p1 * limit->p2.p2_slow;
				target_vco = target * clock.p;

				/* VCO will increase at this point so break */
				if (target_vco > limit->vco.max)
					break;

				if (target_vco < limit->vco.min)
					continue;

				actual_freq = (refclk * clock.m) /
					      (clock.n * clock.p);
				freq_error = 10000 -
					     ((target * 10000) / actual_freq);

				if (freq_error < -min_error) {
					/* freq_error will start to decrease at
					   this point so break */
					break;
				}

				if (freq_error < 0)
					freq_error = -freq_error;

				if (freq_error < min_error) {
					min_error = freq_error;
					*best_clock = clock;
				}
			}
		}
		if (min_error == 0)
			break;
	}

	return min_error == 0;
}

/*
 * Returns a set of divisors for the desired target clock with the given refclk,

Annotation

Implementation Notes