Skip to content

vchiq, fbdev, thermal, cpufreq: Use the new firmware API #1081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions arch/arm/boot/dts/bcm2708_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@

fb: fb {
compatible = "brcm,bcm2708-fb";
firmware = <&firmware>;
status = "disabled";
};

Expand All @@ -225,10 +226,12 @@
reg = <0x7e00b840 0xf>;
interrupts = <0 2>;
cache-line-size = <32>;
firmware = <&firmware>;
};

thermal: thermal {
compatible = "brcm,bcm2835-thermal";
firmware = <&firmware>;
};
};

Expand Down
22 changes: 18 additions & 4 deletions arch/arm/boot/dts/bcm2835-rpi.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@
compatible = "raspberrypi,bcm2835-firmware";
mboxes = <&mailbox>;
};

fb: fb {
compatible = "brcm,bcm2708-fb";
firmware = <&firmware>;
};

thermal: thermal {
compatible = "brcm,bcm2835-thermal";
firmware = <&firmware>;
};

vchiq: vchiq {
compatible = "brcm,bcm2835-vchiq";
reg = <0x7e00b840 0xf>;
interrupts = <0 2>;
cache-line-size = <32>;
firmware = <&firmware>;
};
};

/* Onboard audio */
Expand Down Expand Up @@ -101,10 +119,6 @@
bus-width = <4>;
};

&fb {
status = "okay";
};

/ {
__overrides__ {
i2s = <&i2s>,"status";
Expand Down
15 changes: 0 additions & 15 deletions arch/arm/boot/dts/bcm2835.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -160,21 +160,6 @@
arm-pmu {
compatible = "arm,arm1176-pmu";
};

fb: fb {
compatible = "brcm,bcm2708-fb";
status = "disabled";
};

vchiq: vchiq {
compatible = "brcm,bcm2835-vchiq";
reg = <0x7e00b840 0xf>;
interrupts = <0 2>;
};

thermal: thermal {
compatible = "brcm,bcm2835-thermal";
};
};

clocks {
Expand Down
117 changes: 53 additions & 64 deletions drivers/cpufreq/bcm2835-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cpufreq.h>
#include <linux/platform_data/mailbox-bcm2708.h>
#include <soc/bcm2835/raspberrypi-firmware.h>

/* ---------- DEFINES ---------- */
/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
Expand All @@ -43,23 +43,6 @@
#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)

/* tag part of the message */
struct vc_msg_tag {
uint32_t tag_id; /* the message id */
uint32_t buffer_size; /* size of the buffer (which in this case is always 8 bytes) */
uint32_t data_size; /* amount of data being sent or received */
uint32_t dev_id; /* the ID of the clock/voltage to get or set */
uint32_t val; /* the value (e.g. rate (in Hz)) to set */
};

/* message structure to be sent to videocore */
struct vc_msg {
uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
struct vc_msg_tag tag; /* the tag structure above to make */
uint32_t end_tag; /* an end identifier, should be set to NULL */
};

/* ---------- GLOBALS ---------- */
static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */

Expand All @@ -74,62 +57,63 @@ static struct cpufreq_frequency_table bcm2835_freq_table[] = {
clk_rate either gets or sets the clock rates.
===============================================
*/
static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)

static int bcm2835_cpufreq_clock_property(u32 tag, u32 id, u32 *val)
{
int s, actual_rate=0;
struct vc_msg msg;
struct rpi_firmware *fw = rpi_firmware_get(NULL);
struct {
u32 id;
u32 val;
} packet;
int ret;

packet.id = id;
packet.val = *val;
ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
if (ret)
return ret;

/* wipe all previous message data */
memset(&msg, 0, sizeof msg);
*val = packet.val;

msg.msg_size = sizeof msg;
return 0;
}

msg.tag.tag_id = VCMSG_SET_CLOCK_RATE;
msg.tag.buffer_size = 8;
msg.tag.data_size = 8; /* we're sending the clock ID and the new rates which is a total of 2 words */
msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
msg.tag.val = arm_rate * 1000;
static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
{
u32 rate = arm_rate * 1000;
int ret;

/* send the message */
s = bcm_mailbox_property(&msg, sizeof msg);
ret = bcm2835_cpufreq_clock_property(RPI_FIRMWARE_SET_CLOCK_RATE, VCMSG_ID_ARM_CLOCK, &rate);
if (ret) {
print_err("Failed to set clock: %d (%d)\n", arm_rate, ret);
return 0;
}

/* check if it was all ok and return the rate in KHz */
if (s == 0 && (msg.request_code & 0x80000000))
actual_rate = msg.tag.val/1000;
rate /= 1000;
print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, rate);

print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, actual_rate);
return actual_rate;
return rate;
}

static uint32_t bcm2835_cpufreq_get_clock(int tag)
{
int s;
int arm_rate = 0;
struct vc_msg msg;

/* wipe all previous message data */
memset(&msg, 0, sizeof msg);

msg.msg_size = sizeof msg;
msg.tag.tag_id = tag;
msg.tag.buffer_size = 8;
msg.tag.data_size = 4; /* we're just sending the clock ID which is one word long */
msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
u32 rate;
int ret;

/* send the message */
s = bcm_mailbox_property(&msg, sizeof msg);

/* check if it was all ok and return the rate in KHz */
if (s == 0 && (msg.request_code & 0x80000000))
arm_rate = msg.tag.val/1000;
ret = bcm2835_cpufreq_clock_property(tag, VCMSG_ID_ARM_CLOCK, &rate);
if (ret) {
print_err("Failed to get clock (%d)\n", ret);
return 0;
}

print_debug("%s frequency = %d\n",
tag == VCMSG_GET_CLOCK_RATE ? "Current":
tag == VCMSG_GET_MIN_CLOCK ? "Min":
tag == VCMSG_GET_MAX_CLOCK ? "Max":
"Unexpected", arm_rate);
rate /= 1000;
print_debug("%s frequency = %u\n",
tag == RPI_FIRMWARE_GET_CLOCK_RATE ? "Current":
tag == RPI_FIRMWARE_GET_MIN_CLOCK_RATE ? "Min":
tag == RPI_FIRMWARE_GET_MAX_CLOCK_RATE ? "Max":
"Unexpected", rate);

return arm_rate;
return rate;
}

/*
Expand Down Expand Up @@ -165,9 +149,14 @@ static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
/* measured value of how long it takes to change frequency */
const unsigned int transition_latency = 355000; /* ns */

if (!rpi_firmware_get(NULL)) {
print_err("Firmware is not available\n");
return -ENODEV;
}

/* now find out what the maximum and minimum frequencies are */
bcm2835_freq_table[0].frequency = bcm2835_cpufreq_get_clock(VCMSG_GET_MIN_CLOCK);
bcm2835_freq_table[1].frequency = bcm2835_cpufreq_get_clock(VCMSG_GET_MAX_CLOCK);
bcm2835_freq_table[0].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
bcm2835_freq_table[1].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);

print_info("min=%d max=%d\n", bcm2835_freq_table[0].frequency, bcm2835_freq_table[1].frequency);
return cpufreq_generic_init(policy, bcm2835_freq_table, transition_latency);
Expand Down Expand Up @@ -201,8 +190,8 @@ static int bcm2835_cpufreq_driver_target_index(struct cpufreq_policy *policy, un

static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
{
unsigned int actual_rate = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
print_debug("%d: freq=%d\n", cpu, actual_rate);
unsigned int actual_rate = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
print_debug("cpu%d: freq=%d\n", cpu, actual_rate);
return actual_rate <= bcm2835_freq_table[0].frequency ? bcm2835_freq_table[0].frequency : bcm2835_freq_table[1].frequency;
}

Expand Down
17 changes: 9 additions & 8 deletions drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@
#include <linux/dma-mapping.h>
#include <linux/version.h>
#include <linux/io.h>
#include <linux/platform_data/mailbox-bcm2708.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <asm/pgtable.h>
#include <soc/bcm2835/raspberrypi-firmware.h>

#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)

Expand Down Expand Up @@ -89,10 +89,12 @@ free_pagelist(PAGELIST_T *pagelist, int actual);
int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
{
struct device *dev = &pdev->dev;
struct rpi_firmware *fw = platform_get_drvdata(pdev);
VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
struct resource *res;
void *slot_mem;
dma_addr_t slot_phys;
u32 channelbase;
int slot_mem_size, frag_mem_size;
int err, irq, i;

Expand Down Expand Up @@ -157,13 +159,12 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
}

/* Send the base address of the slots to VideoCore */

dsb(); /* Ensure all writes have completed */

err = bcm_mailbox_write(MBOX_CHAN_VCHIQ, (unsigned int)slot_phys);
if (err) {
dev_err(dev, "mailbox write failed\n");
return err;
channelbase = slot_phys;
err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
&channelbase, sizeof(channelbase));
if (err || channelbase) {
dev_err(dev, "failed to set channelbase\n");
return err ? : -ENXIO;
}

vchiq_log_info(vchiq_arm_log_level,
Expand Down
17 changes: 17 additions & 0 deletions drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
#include <linux/bug.h>
#include <linux/semaphore.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <soc/bcm2835/raspberrypi-firmware.h>

#include "vchiq_core.h"
#include "vchiq_ioctl.h"
Expand Down Expand Up @@ -2793,9 +2795,24 @@ void vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,

static int vchiq_probe(struct platform_device *pdev)
{
struct device_node *fw_node;
struct rpi_firmware *fw;
int err;
void *ptr_err;

fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
/* Remove comment when booting without Device Tree is no longer supported
if (!fw_node) {
dev_err(&pdev->dev, "Missing firmware node\n");
return -ENOENT;
}
*/
fw = rpi_firmware_get(fw_node);
if (!fw)
return -EPROBE_DEFER;

platform_set_drvdata(pdev, fw);

/* create debugfs entries */
err = vchiq_debugfs_init();
if (err != 0)
Expand Down
Loading