diff --git a/tools/Makefile.sources b/tools/Makefile.sources
index b85a6b8..2bea389 100644
--- a/tools/Makefile.sources
+++ b/tools/Makefile.sources
@@ -14,6 +14,7 @@ bin_PROGRAMS = 				\
 	intel_dump_decode 		\
 	intel_error_decode 		\
 	intel_forcewaked		\
+	intel_frequency			\
 	intel_framebuffer_dump 		\
 	intel_gpu_time 			\
 	intel_gpu_top 			\
diff --git a/tools/intel_frequency.c b/tools/intel_frequency.c
new file mode 100644
index 0000000..59f3814
--- /dev/null
+++ b/tools/intel_frequency.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Example:
+ * Get all frequencies:
+ * intel_frequency --get=cur,min,max,eff
+ *
+ * Same as above:
+ * intel_frequency -g
+ *
+ * Get the efficient frequency:
+ * intel_frequency -geff
+ *
+ * Lock the GPU frequency to 300MHz:
+ * intel_frequency --set min=300
+ *
+ * Set the maximum frequency to 900MHz:
+ * intel_frequency --custom max=900
+ *
+ * Lock the GPU frequency to its maximum frequency:
+ * intel_frequency --max
+ *
+ * Lock the GPU frequency to its most efficient frequency:
+ * intel_frequency -e
+ *
+ * Lock The GPU frequency to its minimum frequency:
+ * intel_frequency --min
+ *
+ * Reset the GPU to hardware defaults
+ * intel_frequency -d
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "drmtest.h"
+#include "intel_chipset.h"
+
+static int device, devid;
+
+enum {
+	CUR=0,
+	MIN,
+	EFF,
+	MAX,
+	RP0,
+	RPn
+};
+
+struct freq_info {
+	const char *name;
+	const char *mode;
+	FILE *filp;
+	char *path;
+};
+
+static struct freq_info info[] = {
+	{ "cur", "r"  },
+	{ "min", "rb+" },
+	{ "RP1", "r" },
+	{ "max", "rb+" },
+	{ "RP0", "r" },
+	{ "RPn", "r" }
+};
+
+static char *
+get_sysfs_path(const char *which)
+{
+	static const char fmt[] = "/sys/class/drm/card%1d/gt_%3s_freq_mhz";
+	char *path;
+	int ret;
+
+#define STATIC_STRLEN(string) (sizeof(string) / sizeof(string [0]))
+	ret = asprintf(&path, fmt, device, which);
+	assert(ret == (STATIC_STRLEN(fmt) - 3));
+#undef STATIC_STRLEN
+
+	return path;
+}
+
+static void
+initialize_freq_info(struct freq_info *freq_info)
+{
+	if (freq_info->filp)
+		return;
+
+	freq_info->path = get_sysfs_path(freq_info->name);
+	assert(freq_info->path);
+	freq_info->filp = fopen(freq_info->path, freq_info->mode);
+	assert(freq_info->filp);
+}
+
+static void wait_freq_settle(void)
+{
+	struct timespec ts;
+
+	/* FIXME: Lazy sleep without check. */
+	ts.tv_sec = 0;
+	ts.tv_nsec = 20000;
+	clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
+}
+
+static void set_frequency(struct freq_info *freq_info, int val)
+{
+	initialize_freq_info(freq_info);
+	rewind(freq_info->filp);
+	assert(fprintf(freq_info->filp, "%d", val) > 0);
+
+	wait_freq_settle();
+}
+
+static int get_frequency(struct freq_info *freq_info)
+{
+	int val;
+
+	initialize_freq_info(freq_info);
+	rewind(freq_info->filp);
+	assert(fscanf(freq_info->filp, "%d", &val)==1);
+
+	return val;
+}
+
+static void
+usage(const char *prog)
+{
+	printf("Usage: %s [-e] [--min | --max] [-g (min|max|efficient)] [-s frequency_mhz]\n\n", prog);
+	printf("%s A program to manipulate Intel GPU frequencies.\n\n", prog);
+	printf("Options: \n");
+	printf("  -e		Lock frequency to the most efficient frequency\n");
+	printf("  -g, --get=    Get the frequency (optional arg: \"cur\"|\"min\"|\"max\"|\"eff\")\n");
+	printf("  -s, --set     Lock frequency to an absolute value (MHz)\n");
+	printf("  -c, --custom  Set a min, or max frequency \"min=X | max=Y\"\n");
+	printf("  -m  --max     Lock frequency to max frequency\n");
+	printf("  -i  --min     Lock frequency to min (never a good idea, DEBUG ONLY)\n");
+	printf("  -d  --defaults  Return the system to hardware defaults\n");
+	printf("Examples:\n");
+	printf("\tintel_frequency -gmin,cur Get the current and minimum frequency\n");
+	printf("\tintel_frequency -s 400    Lock frequency to 400Mhz\n");
+	printf("\tintel_frequency -c max=750 Set the max frequency to 750MHz\n");
+	exit(EXIT_FAILURE);
+}
+
+/* Returns read or write operation */
+static bool
+parse(int argc, char *argv[], bool *act_upon, int *new_freq)
+{
+	int c, tmp;
+	bool write = false;
+
+	char *token[] = {
+		(char *)info[CUR].name,
+		(char *)info[MIN].name,
+		(char *)"eff",
+		(char *)info[MAX].name
+	};
+
+	/* No args means -g" */
+	if (argc == 1) {
+		for (c = 0; c < ARRAY_SIZE(act_upon); c++)
+			act_upon[c] = true;
+		goto done;
+	}
+	while (1) {
+		int option_index = 0;
+		static struct option long_options[] = {
+			{ "get", optional_argument, NULL, 'g' },
+			{ "set", required_argument, NULL, 's' },
+			{ "custom", required_argument, NULL, 'c'},
+			{ "min", no_argument, NULL, 'i' },
+			{ "max", no_argument, NULL, 'm' },
+			{ "defaults", no_argument, NULL, 'd' },
+			{ "help", no_argument, NULL, 'h' },
+			{ NULL, 0, NULL, 0}
+		};
+
+		c = getopt_long(argc, argv, "eg::s:c:midh", long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'g':
+			if (write == true)
+				fprintf(stderr, "Read and write operations not support simultaneously.\n");
+
+			if (optarg) {
+				char *value, *subopts = optarg;
+				int x;
+				while (*subopts != '\0') {
+					x = getsubopt(&subopts, token, &value);
+					if (x == -1) {
+						fprintf(stderr, "Unrecognized option (%s)\n", value);
+						break;
+					} else
+						act_upon[x] = true;
+				}
+			} else {
+				int i;
+				for (i = 0; i < ARRAY_SIZE(act_upon); i++)
+					act_upon[i] = true;
+			}
+			break;
+		case 's':
+			if (!optarg)
+				usage(argv[0]);
+
+			if (write == true) {
+				fprintf(stderr, "Only one write may be specified at a time\n");
+				exit(EXIT_FAILURE);
+			}
+
+			write = true;
+			act_upon[MIN] = true;
+			act_upon[MAX] = true;
+			sscanf(optarg, "%d", &new_freq[MAX]);
+			new_freq[MIN] = new_freq[MAX];
+			break;
+		case 'c':
+			if (!optarg)
+				usage(argv[0]);
+
+			if (write == true) {
+				fprintf(stderr, "Only one write may be specified at a time\n");
+				exit(EXIT_FAILURE);
+			}
+
+			write = true;
+
+			if (!strncmp("min=", optarg, 4)) {
+				act_upon[MIN] = true;
+				sscanf(optarg+4, "%d", &new_freq[MIN]);
+			} else if (!strncmp("max=", optarg, 4)) {
+				act_upon[MAX] = true;
+				sscanf(optarg+4, "%d", &new_freq[MAX]);
+			} else {
+				fprintf(stderr, "Selected unmodifiable frequency\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'e': /* efficient */
+			if (IS_VALLEYVIEW(devid) || IS_CHERRYVIEW(devid)) {
+				/* the LP parts have special efficient frequencies */
+				fprintf(stderr,
+					"FIXME: Warning efficient frequency information is incorrect.\n");
+				exit(EXIT_FAILURE);
+			}
+			tmp = get_frequency(&info[EFF]);
+			new_freq[MIN] = tmp;
+			new_freq[MAX] = tmp;
+			act_upon[MIN] = true;
+			act_upon[MAX] = true;
+			write = true;
+			break;
+		case 'i': /* mIn */
+			tmp = get_frequency(&info[RPn]);
+			new_freq[MIN] = tmp;
+			new_freq[MAX] = tmp;
+			act_upon[MIN] = true;
+			act_upon[MAX] = true;
+			write = true;
+			break;
+		case 'm': /* max */
+			tmp = get_frequency(&info[RP0]);
+			new_freq[MIN] = tmp;
+			new_freq[MAX] = tmp;
+			act_upon[MIN] = true;
+			act_upon[MAX] = true;
+			write = true;
+			break;
+		case 'd': /* defaults */
+			new_freq[MIN] = get_frequency(&info[RPn]);
+			new_freq[MAX] = get_frequency(&info[RP0]);
+			act_upon[MIN] = true;
+			act_upon[MAX] = true;
+			write = true;
+			break;
+		case 'h':
+		default:
+			usage(argv[0]);
+		}
+	}
+
+done:
+	return write;
+}
+
+int main(int argc, char *argv[])
+{
+
+	bool write, fail, targets[MAX+1] = {false};
+	int i, try = 1, set_freq[MAX+1] = {0};
+
+	devid = intel_get_drm_devid(drm_open_any());
+	device = drm_get_card();
+
+	write = parse(argc, argv, targets, set_freq);
+	fail = write;
+
+	/* If we've previously locked the frequency, we need to make sure to set things
+	 * in the correct order, or else the operation will fail (ie. min = max = 200,
+	 * and we set min to 300, we fail because it would try to set min >
+	 * max). This can be accomplished be going either forward or reverse
+	 * through the loop. MIN is always before MAX.
+	 *
+	 * XXX: Since only min and max are at play, the super lazy way is to do this
+	 * 3 times and if we still fail after 3, it's for real.
+	 */
+again:
+	if (try > 2) {
+		fprintf(stderr, "Did not achieve desired freq.\n");
+		exit(EXIT_FAILURE);
+	}
+	for (i = 0; i < ARRAY_SIZE(targets); i++) {
+		if (targets[i] == false)
+			continue;
+
+		if (write) {
+			set_frequency(&info[i], set_freq[i]);
+			if (get_frequency(&info[i]) != set_freq[i])
+				fail = true;
+			else
+				fail = false;
+		} else {
+			printf("%s: %d MHz\n", info[i].name, get_frequency(&info[i]));
+		}
+	}
+
+	if (fail) {
+		try++;
+		goto again;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(targets); i++) {
+		if (info[i].filp) {
+			fclose(info[i].filp);
+			free(info[i].path);
+		}
+	}
+
+	return EXIT_SUCCESS;
+}
