UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Adventurer
Adventurer
6,761 Views
Registered: ‎12-16-2013

Problem with stopping the PL clock in zynq/Linux

Jump to solution

Hi All,

 

I am woking on Zynq using Linux.

I want to stop/start the PL clock to implement clock gating.

I can change the PL clock frequency through software.

Bu when I use the Clock Throttle explained in UG858-Zynq TRM manual

The clock still running.

 

Also, I am using the Vivado-HLS to generate the IP and Vivado to create the SoC.

 

Any kind of help will be appreciated

 

Mohava

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Adventurer
Adventurer
6,119 Views
Registered: ‎12-16-2013

Re: Problem with stopping the PL clock in zynq/Linux

Jump to solution

Hi,

 

I found the solution and this is the code that worked for me, maybe it is useful for others

 

 

u32 ps_frequency_set(int divisor) {
int fd;

unsigned page_addr, page_offset;

void *ptr, *ptr_sta, *ptr_ddr;
unsigned page_size=sysconf(_SC_PAGESIZE);


/* Open /dev/mem file */
fd = open ("/dev/mem", O_RDWR);
if (fd < 1) {
perror("error 1\n");
return -1;
}

if (divisor > 63) {
printf("The PS frequncy divider cannot be divided by %d\n", divisor);
divisor = 62;
printf("The PS frequncy divider is set to the maximum which is 62\n");
}
if (divisor < 2) {
printf("The PS frequncy cannot divided by %d\n", divisor);
divisor = 2;
printf("The PS frequncy divider is set to default which is 2\n");
}

//enable SLCR_UNLOCK
unsigned slcr_unlock = 0xF8000008;

page_addr = (slcr_unlock & (~(page_size-1)));
page_offset = slcr_unlock - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0xDF0D;

 

unsigned long arm_clk_ctrl = 0xF8000120;

page_addr = (arm_clk_ctrl & (~(page_size-1)));
page_offset = arm_clk_ctrl - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

unsigned int arm_clk_ctrl_value = *((int *)(ptr + page_offset));

printf("original arm_clk_ctrl_value = 0x%08x\n", arm_clk_ctrl_value);

u32 divisor_MASK = 0xFFFFC0FF;
arm_clk_ctrl_value = arm_clk_ctrl_value&divisor_MASK;

divisor = divisor << 8;

arm_clk_ctrl_value = arm_clk_ctrl_value|divisor;

*((int *)(ptr + page_offset)) = arm_clk_ctrl_value;//0x00102000;

printf("updated arm_clk_ctrl_value = 0x%08x\n", arm_clk_ctrl_value);


close(fd);
return 0;

}

0 Kudos
2 Replies
Highlighted
Adventurer
Adventurer
6,120 Views
Registered: ‎12-16-2013

Re: Problem with stopping the PL clock in zynq/Linux

Jump to solution

Hi,

 

I found the solution and this is the code that worked for me, maybe it is useful for others

 

 

u32 ps_frequency_set(int divisor) {
int fd;

unsigned page_addr, page_offset;

void *ptr, *ptr_sta, *ptr_ddr;
unsigned page_size=sysconf(_SC_PAGESIZE);


/* Open /dev/mem file */
fd = open ("/dev/mem", O_RDWR);
if (fd < 1) {
perror("error 1\n");
return -1;
}

if (divisor > 63) {
printf("The PS frequncy divider cannot be divided by %d\n", divisor);
divisor = 62;
printf("The PS frequncy divider is set to the maximum which is 62\n");
}
if (divisor < 2) {
printf("The PS frequncy cannot divided by %d\n", divisor);
divisor = 2;
printf("The PS frequncy divider is set to default which is 2\n");
}

//enable SLCR_UNLOCK
unsigned slcr_unlock = 0xF8000008;

page_addr = (slcr_unlock & (~(page_size-1)));
page_offset = slcr_unlock - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0xDF0D;

 

unsigned long arm_clk_ctrl = 0xF8000120;

page_addr = (arm_clk_ctrl & (~(page_size-1)));
page_offset = arm_clk_ctrl - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

unsigned int arm_clk_ctrl_value = *((int *)(ptr + page_offset));

printf("original arm_clk_ctrl_value = 0x%08x\n", arm_clk_ctrl_value);

u32 divisor_MASK = 0xFFFFC0FF;
arm_clk_ctrl_value = arm_clk_ctrl_value&divisor_MASK;

divisor = divisor << 8;

arm_clk_ctrl_value = arm_clk_ctrl_value|divisor;

*((int *)(ptr + page_offset)) = arm_clk_ctrl_value;//0x00102000;

printf("updated arm_clk_ctrl_value = 0x%08x\n", arm_clk_ctrl_value);


close(fd);
return 0;

}

0 Kudos
Adventurer
Adventurer
3,268 Views
Registered: ‎12-16-2013

Re: Problem with stopping the PL clock in zynq/Linux

Jump to solution

PL enable and disable functions

 

 

 

 

u32 pl_disable_clock(int pl_clock) {

int fd;

unsigned page_addr, page_offset;

void *ptr, *ptr_sta, *ptr_ddr;
unsigned page_size=sysconf(_SC_PAGESIZE);


unsigned long int fpga_thr_ctrl;
unsigned long int fpga_thr_cnt;

if (pl_clock == FPGA0_CLK) {
fpga_thr_ctrl = FPGA0_THR_CTRL;
fpga_thr_cnt = FPGA0_THR_CNT;
}
if (pl_clock == FPGA1_CLK) {
fpga_thr_ctrl = FPGA1_THR_CTRL;
fpga_thr_cnt = FPGA1_THR_CNT;
}
if (pl_clock == FPGA2_CLK) {
fpga_thr_ctrl = FPGA2_THR_CTRL;
fpga_thr_cnt = FPGA2_THR_CNT;
}
if (pl_clock == FPGA3_CLK) {
fpga_thr_ctrl = FPGA3_THR_CTRL;
fpga_thr_cnt = FPGA3_THR_CNT;
}

 

/* Open /dev/mem file */
fd = open ("/dev/mem", O_RDWR);
if (fd < 1) {
perror("error 1\n");
return -1;
}

//enable SLCR_UNLOCK
unsigned slcr_unlock = 0xF8000008;

page_addr = (slcr_unlock & (~(page_size-1)));
page_offset = slcr_unlock - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0xDF0D;


//enable LVL_SHIFT_EN
unsigned lvl_shiftr_en = 0xF8000900;

page_addr = (lvl_shiftr_en & (~(page_size-1)));
page_offset = lvl_shiftr_en - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0x0F;

 

 

//zynq_slcr_write 1-->FPGA0_THR_CNT_OFFSET
page_addr = (fpga_thr_cnt & (~(page_size-1)));
page_offset = fpga_thr_cnt - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 1;

 


//zynq_slcr_write 1-->FPGA0_THR_CTRL_OFFSET
page_addr = (fpga_thr_ctrl & (~(page_size-1)));
page_offset = fpga_thr_ctrl - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 1;


close(fd);
return 0;


}


u32 pl_enable_clock(int pl_clock) {

int fd;

unsigned page_addr, page_offset;

void *ptr, *ptr_sta, *ptr_ddr;
unsigned page_size=sysconf(_SC_PAGESIZE);


unsigned long int fpga_thr_ctrl;
unsigned long int fpga_thr_cnt;

if (pl_clock == FPGA0_CLK) {
fpga_thr_ctrl = FPGA0_THR_CTRL;
fpga_thr_cnt = FPGA0_THR_CNT;
}
if (pl_clock == FPGA1_CLK) {
fpga_thr_ctrl = FPGA1_THR_CTRL;
fpga_thr_cnt = FPGA1_THR_CNT;
}
if (pl_clock == FPGA2_CLK) {
fpga_thr_ctrl = FPGA2_THR_CTRL;
fpga_thr_cnt = FPGA2_THR_CNT;
}
if (pl_clock == FPGA3_CLK) {
fpga_thr_ctrl = FPGA3_THR_CTRL;
fpga_thr_cnt = FPGA3_THR_CNT;
}

 

/* Open /dev/mem file */
fd = open ("/dev/mem", O_RDWR);
if (fd < 1) {
perror("error 1\n");
return -1;
}

//enable SLCR_UNLOCK
unsigned slcr_unlock = 0xF8000008;

page_addr = (slcr_unlock & (~(page_size-1)));
page_offset = slcr_unlock - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0xDF0D;


//enable LVL_SHIFT_EN
unsigned lvl_shiftr_en = 0xF8000900;

page_addr = (lvl_shiftr_en & (~(page_size-1)));
page_offset = lvl_shiftr_en - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0x0F;

 

//zynq_slcr_write 0-->FPGA0_THR_CNT_OFFSET
page_addr = (fpga_thr_cnt & (~(page_size-1)));
page_offset = fpga_thr_cnt - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0;

 


//zynq_slcr_write 0-->FPGA0_THR_CTRL_OFFSET
page_addr = (fpga_thr_ctrl & (~(page_size-1)));
page_offset = fpga_thr_ctrl - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);

*((int *)(ptr + page_offset)) = 0;

close(fd);

return 0;


}

 

0 Kudos